如何使用自定义拆分实现扫描程序

时间:2015-10-11 18:34:43

标签: go

我有一个日志文件,我需要使用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
            }
    }

谢谢,

4 个答案:

答案 0 :(得分:10)

Scanner类型有一个名为Split的函数,它允许您传递SplitFunc以确定扫描程序如何拆分给定的字节切片。默认SplitFuncScanLines,您可以看到implementation source。从这一点开始,您可以根据自己的特定格式编写自己的SplitFunc来打破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
}

您可以在https://play.golang.org/p/ecCYkTzme4看到示例的完整实现。该文档将提供实现此类内容所需的所有见解。

答案 1 :(得分:1)

Ben Campbellsto-b-doo的稍微优化的解决方案

将字节片转换为字符串似乎是很繁重的操作。

在我用于日志处理的应用程序中,它成为了瓶颈。

仅以字节为单位的数据就可以为我的应用程序带来〜1500%的性能提升。

Double

答案 2 :(得分:0)

Ben Campbell's answer包裹在一个函数中,该函数返回用于子字符串的splitfunc:

demo on play.golang.org

欢迎提出改进建议

// 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
    }
}

答案 3 :(得分:0)

希望比 stu0292's improvements 有所改进(可能是可读性) 并使用最终令牌信号。

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

      // 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 !atEOF {
         return 0, nil, nil
       }
     return len(data), data, bufio.ErrFinalToken
  }
}