Go 如何使用自定义拆分实现扫描仪
我有一个日志文件,需要使用golang解析其中的每条记录。 每条记录以“#”开头,一条记录可以跨越一行或多行:Go 如何使用自定义拆分实现扫描仪,go,Go,我有一个日志文件,需要使用golang解析其中的每条记录。 每条记录以“#”开头,一条记录可以跨越一行或多行: # Line1 # Line2 Continued line2 Continued line2 # line3 ..... 一些代码:),我是初学者 f, _ := os.Open(mylog) scanner := bufio.NewScanner(f) var queryRec string for scanner.Scan() {
# Line1
# Line2
Continued line2
Continued line2
# line3
.....
一些代码:),我是初学者
f, _ := os.Open(mylog)
scanner := bufio.NewScanner(f)
var queryRec string
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, "# ") && len(queryRec) == 0 {
queryRec = line
} else if !strings.HasPrefix(line, "# ") && len(queryRec) == 0 {
fmt.Println("There is a big problem!!!")
} else if !strings.HasPrefix(line, "# ") && len(queryRec) != 0 {
queryRec += line
} else if strings.HasPrefix(line, "# ") && len(queryRec) != 0 {
queryRec = line
}
}
谢谢,该类型有一个名为的函数,该函数允许您传递一个值,以确定扫描仪将如何分割给定的字节片。默认值是您可以看到的。从这一点上,您可以根据自己的特定格式编写自己的内容,以打破bufio.Reader
内容
func crunchSplitFunc(data []byte, atEOF bool) (advance int, token []byte, err error) {
// Return nothing if at end of file and no data passed
if atEOF && len(data) == 0 {
return 0, nil, nil
}
// Find the index of the input of a newline followed by a
// pound sign.
if i := strings.Index(string(data), "\n#"); i >= 0 {
return i + 1, data[0:i], nil
}
// If at end of file with data return the data
if atEOF {
return len(data), data, nil
}
return
}
您可以在中看到该示例的完整实现。文档将提供实现类似功能所需的所有洞察力 封装到一个func中,该func返回子字符串的splitfunc:
欢迎提出改善建议
// SplitAt returns a bufio.SplitFunc closure, splitting at a substring
// scanner.Split(SplitAt("\n# "))
func SplitAt(substring string) func(data []byte, atEOF bool) (advance int, token []byte, err error) {
return func(data []byte, atEOF bool) (advance int, token []byte, err error) {
// Return nothing if at end of file and no data passed
if atEOF && len(data) == 0 {
return 0, nil, nil
}
// Find the index of the input of the separator substring
if i := strings.Index(string(data), substring); i >= 0 {
return i + len(substring), data[0:i], nil
}
// If at end of file with data return the data
if atEOF {
return len(data), data, nil
}
return
}
}
和的稍微优化的解决方案 将字节片转换为字符串似乎是一项相当繁重的操作 在我的日志处理应用程序中,它成为一个瓶颈 只需将数据保存在字节中,我的应用程序的性能就可以提升约1500%
func SplitAt(substring string) func(data []byte, atEOF bool) (advance int, token []byte, err error) {
searchBytes := []byte(substring)
searchLen := len(searchBytes)
return func(data []byte, atEOF bool) (advance int, token []byte, err error) {
dataLen := len(data)
// Return nothing if at end of file and no data passed
if atEOF && dataLen == 0 {
return 0, nil, nil
}
// Find next separator and return token
if i := bytes.Index(data, searchBytes); i >= 0 {
return i + searchLen, data[0:i], nil
}
// If we're at EOF, we have a final, non-terminated line. Return it.
if atEOF {
return dataLen, data, nil
}
// Request more data.
return 0, nil, nil
}
}
向我们展示您已经编写的代码,解释您遇到的问题,以及您认为这可能很难的原因。我正在尝试读取每条记录,并将其放入mysql数据库@PedroLobitoAdded一些代码@gbulmerNow,有什么问题?错误?输出错误?我的问题:1。如何处理日志文件中的最后一行?2.有一种更优化/更优雅的方式来实现同样的目标?谢谢@benjic。优雅的解决方案,如预期的那样工作:)当输入数据在
#
s之前包含多个换行符时,这将是一个问题。