我们经常会遇到解析某些自定义分隔的一串数列的问题。比如文章中的单词以空格分隔,csv格式或者临时由两种符号分隔的二维表数据。这些数据用JSON,TOML描述又太笨重,要的就是简简单单编码与解析。因此可以利用Scanner来完成。
import (
"fmt"
"bufio"
"bytes"
"strings"
)
func main() {
var str = "姓名;年龄;籍贯;性别\r\nTom,15,China,male"
rd := strings.NewReader(str)
//NewScanner接受实现io.Reader接口的参数,
//因此解析的源可以是file,string,os.Stdin等等
line := bufio.NewScanner(rd)
//设定分隔方式,由于是函数作为参数,因此可以实现复杂的分隔方式,比如完整版csv格式分隔
//分拆函数原型为
//type SplitFunc func(data []byte, atEOF bool) (advance int, token []byte, err error)
//语言自带换行符分隔
line.Split(bufio.ScanLines)
//循环拆分项
for line.Scan() {
//fmt.Println(line.Text())
//每Scan一次可以通过line.Text()或者line.Bytes()获取分隔的单项
item := bufio.NewScanner(strings.NewReader(line.Text()))
item.Split(ScanItems)
item.Scan()
it1 := item.Text()
item.Scan()
it2 := item.Text()
item.Scan()
it3 := item.Text()
item.Scan()
it4 := item.Text()
fmt.Println(it1 + " " + it2 + " " + it3 + " " + it4)
if item.Err() != nil {
//TODO: 解析过程中出现错误,但不一定会抛出异常
fmt.Println(item.Err())
}
}
}
//逗号或分号 的自定义分隔
func ScanItems(data []byte, atEOF bool) (advance int, token []byte, err error) {
if atEOF && len(data) == 0 {
return 0, nil, nil
}
if i := bytes.IndexAny(data, ",;"); i >= 0 {
return i + 1, data[0:i], nil
}
if atEOF {
return len(data), data, nil
}
return 0, nil, nil
}
Output:
姓名 年龄 籍贯 性别
Tom 15 China male