相当于C的否定扫描集

时间:2017-06-03 18:08:46

标签: go scanf gofmt

模仿C中存在的否定扫描集的方法是什么?

示例输入字符串:aaaa, bbbb

继续使用:

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

结果仅str1设置为:aaaa,

在C中,可以使用格式字符串"%[^,], %s"来避免这个问题,有没有办法在go中完成此操作?

2 个答案:

答案 0 :(得分:2)

Go并不像C那样直接支持,部分原因是你应该读一行并使用像strings.FieldsFunc这样的东西。但这自然是一种非常简单的观点。对于以同类方式格式化的数据,您可以使用bufio.Scanner基本上对任何io.Reader执行相同的操作。但是,如果你不得不处理这种格式:

// Name; email@domain
//
// 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的扫描仪,但它足够接近。如上所述,即使使用格式化输入,您也应该验证数据,因为格式化缺少上下文(在处理格式时添加它会违反KISS原则并使代码的可读性变差)。

例如,像[A-Za-z]([A-Za-z0-9-]?.)[A-Za-z0-9]这样的简短正则表达式不足以验证域名,而简单的扫描集只相当于[A-Za-z0-9.-]。但是,扫描集足以从文件或您可能正在使用的任何其他读取器扫描字符串,但仅仅验证字符串是不够的。为此,一个正则表达式甚至一个合适的库将是一个更好的选择。

答案 1 :(得分:1)

你总是可以选择正则表达式;

setState