Go 如何使用自定义拆分实现扫描仪

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() {

我有一个日志文件,需要使用golang解析其中的每条记录。 每条记录以“#”开头,一条记录可以跨越一行或多行:

# 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之前包含多个换行符时,这将是一个问题。