Cに存在する否定型スキャンセットを模倣する方法は何ですか?例えば、入力文字列のためCにネゲートされたスキャンセットに相当するもの
:aaaa, bbbb
において使用行く:aaaa,
Cは、1つの"%[^,], %s"
としてフォーマット文字列を使用することができる:
fmt.Sscanf(input, "%s, %s", &str1, &str2)
結果のみstr1
は、以下のように設定されていますこの問題を回避するには、これを実現する方法がありますか?
Cに存在する否定型スキャンセットを模倣する方法は何ですか?例えば、入力文字列のためCにネゲートされたスキャンセットに相当するもの
:aaaa, bbbb
において使用行く:aaaa,
Cは、1つの"%[^,], %s"
としてフォーマット文字列を使用することができる:
fmt.Sscanf(input, "%s, %s", &str1, &str2)
結果のみstr1
は、以下のように設定されていますこの問題を回避するには、これを実現する方法がありますか?
Goが部分的に、直接Cのようにこの機能をサポートしていません。しかし、それは当然非常に単純な見方です。均質にフォーマットされたデータの場合は、bufio.Scanner
を使用して、io.Reader
で本質的に同じことを行うことができます。あなたはこの形式のようなものに対処しなければならなかった場合は、:
// Name; [email protected]
//
// Anything other than ';' is valid for name.
// Anything before '@' is valid for email.
// For domain, only A-Z, a-z, and 0-9, as well as '-' and '.' are valid.
sscanf("%[^;]; %[^@]@%[-." ALNUM "]", name, email, domain);
をあなたは今、特定の状態を扱っているので、あなたはトラブルに実行したいです。そのような場合、手動で物事を解析するには、bufio.Reader
で作業することを好むかもしれません。 fmt.Scanner
を実装するオプションもあります。ここではあなたにそれがfmt.Scanner
を実装することができますどのように簡単なのアイデアを与えるためにいくつかのサンプルコードがあります:
// Scanset acts as a filter when scanning strings.
// The zero value of a Scanset will discard all non-whitespace characters.
type Scanset struct {
ps *string
delimFunc func(rune) bool
}
// Create a new Scanset to filter delimiter characters.
// Once f(delimChar) returns false, scanning will end.
// If s is nil, characters for which f(delimChar) returns true are discarded.
// If f is nil, !unicode.IsSpace(delimChar) is used
// (i.e. read until unicode.IsSpace(delimChar) returns true).
func NewScanset(s *string, f func(r rune) bool) *Scanset {
return &Scanset{
ps: s,
delimFunc: f,
}
}
// Scan implements the fmt.Scanner interface for the Scanset type.
func (s *Scanset) Scan(state fmt.ScanState, verb rune) error {
if verb != 'v' && verb != 's' {
return errors.New("scansets only work with %v and %s verbs")
}
tok, err := state.Token(false, s.delimFunc)
if err != nil {
return err
}
if s.ps != nil {
*s.ps = string(tok)
}
return nil
}
これは、Cのscansetsはないが、それは十分に近いです。前述したように、フォーマットされた入力であっても、フォーマットには文脈が欠けているため、データを検証する必要があります(書式を処理する間にKISSの原則に違反し、コードの可読性が悪くなります)。
例えば、のような短い正規表現では、ドメイン名を検証するには不十分であり、単純なスキャンセットは単に[A-Za-z0-9.-]
に相当します。しかし、スキャンセットはファイルや他のどのリーダーからでも文字列をスキャンするのには十分ですが、文字列だけを検証するだけでは不十分です。そのためには、正規表現や適切なライブラリでさえ、はるかに良い選択肢になります。
いつも正規表現に行くことができます。あなたが行を読み取り、strings.FieldsFunc
ようなものを使用しなければならないため
re := regexp.MustCompile(`(\w+), (\w+)`)
input := "aaaa, bbbb"
fmt.Printf("%#v\n", re.FindStringSubmatch(input))
// Prints []string{"aaaa, bbbb", "aaaa", "bbbb"}