2017-06-03 184 views
0

什么是模仿C中存在的否定扫描集的方式?相当于C的否定扫描集

有关示例输入字符串:aaaa, bbbb

在去使用:

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

结果仅str1被设置为:aaaa,

在C人们可以使用一个格式字符串作为"%[^,], %s"为了避免这个问题,有没有办法在去做到这一点?

回答

2

Go不支持这种直接像C,部分原因是因为你应该读一本线,并使用类似strings.FieldsFunc。但这自然是一个非常简单的观点。对于以均匀格式进行格式化的数据,您可以使用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

你总是可以用正则表达式;

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