2017-06-03 9 views
0

Cに存在する否定型スキャンセットを模倣する方法は何ですか?例えば、入力文字列のためCにネゲートされたスキャンセットに相当するもの

aaaa, bbbb

において使用行く:aaaa,

Cは、1つの"%[^,], %s"としてフォーマット文字列を使用することができる:

fmt.Sscanf(input, "%s, %s", &str1, &str2) 

結果のみstr1は、以下のように設定されていますこの問題を回避するには、これを実現する方法がありますか?

答えて

2

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 
} 

Playground example

これは、Cのscansetsはないが、それは十分に近いです。前述したように、フォーマットされた入力であっても、フォーマットには文脈が欠けているため、データを検証する必要があります(書式を処理する間にKISSの原則に違反し、コードの可読性が悪くなります)。

例えば、​​のような短い正規表現では、ドメイン名を検証するには不十分であり、単純なスキャンセットは単に[A-Za-z0-9.-]に相当します。しかし、スキャンセットはファイルや他のどのリーダーからでも文字列をスキャンするのには十分ですが、文字列だけを検証するだけでは不十分です。そのためには、正規表現や適切なライブラリでさえ、はるかに良い選択肢になります。

1

いつも正規表現に行くことができます。あなたが行を読み取り、strings.FieldsFuncようなものを使用しなければならないため

re := regexp.MustCompile(`(\w+), (\w+)`) 
input := "aaaa, bbbb" 
fmt.Printf("%#v\n", re.FindStringSubmatch(input)) 
// Prints []string{"aaaa, bbbb", "aaaa", "bbbb"} 
関連する問題