【问题标题】:Using regexp to parse an Apache log file [duplicate]使用正则表达式解析 Apache 日志文件 [重复]
【发布时间】:2019-08-24 14:37:51
【问题描述】:

我正在解析我自定义的 Apache 日志,只给我两个值:“时间”和“内存”(值是毫秒数和字节数),它们都是 int64 或 float64,但我是使用正则表达式和 Go 来解析文件,所以当我匹配文件的内容时,它返回“[]”(空括号)并且不填充切片,我的代码是:

for _, line := range lines {
    var buffer bytes.Buffer

    buffer.WriteString(`\[0-9]+\s`)
    buffer.WriteString(`[0-9]+\s`)
    re1, err := regexp.Compile(buffer.String())

    if err != nil {
        log.Fatalf("regexp: %s", err)
    }
    result := re1.FindStringSubmatch(line)
    fmt.Println(result)
}

当我打印结果时,它给了我空括号,当我运行整个程序时,它给出的索引超出范围(这是可以理解的,因为结果是空的)。

我的数据如下所示:

1040 3952
2849 6832

【问题讨论】:

  • 你有\[0-9]+\s[0-9]+\s 正则表达式,第一个[ 不应该被转义。您正在使用 FindStringSubmatch 但您的正则表达式没有捕获组。预期的结果是什么?
  • 不要为此使用正则表达式。只需将输入拆分为空格即可。对于这样一个微不足道的例子,正则表达式很慢、很麻烦,而且很难阅读。
  • 如果您只需要匹配带有 2 个数字的行,您可以使用 regexp.Compile(`(?m)^([0-9]+)\s+([0-9]+)$`),请参阅 this demo

标签: regex apache parsing go logging


【解决方案1】:

Regexp 完全不适合这项工作。使用strings.Splitstrings.Fields 会更容易阅读,操作也更快:

for _, line := range lines {
    fields := strings.Fields(line)
    ms := fields[0]
    size := fields[1]
    fmt.Printf("time: %v, size: %v\n", ms, size)
}

如果您想将这些转换为数字,您可以使用 strconv 包轻松完成,另外还有一个好处是它会检测您是否收到意外(非数字)输入):

for _, line := range lines {
    fields := strings.Fields(line)
    ms, err := strconv.Itoa(fields[0])
    if err != nil {
        log.Fatalf("time field: %s", err)
    }
    size, err := strconv.Atoi(fields[1])
    if err != nil {
        log.Fatalf("size field: %s", err)
    }
    fmt.Printf("time: %v, size: %v\n", ms, size)
}


如果你坚持使用正则表达式,至少只编译一次,在你的 for 循环之外:
re, err := regexp.Compile( ... )
if err != nil {
    log.Fatalf("regexp: %s", err)
}
for _, line := range lines {
    result := re.FindStringSubmatch(line)
    fmt.Println(result)
}

【讨论】:

  • 是的,这行得通,实际上我的数据将来可能会发生变化,我可能还需要添加 ip,除了正则表达式之外别无选择。我认为
  • 您仍应使用strings.Fields 方法,只要您的所有字段都不包含空格。
  • 好的,非常感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 2010-09-07
  • 1970-01-01
  • 2014-12-26
  • 2019-07-02
  • 2011-09-12
  • 2016-02-19
相关资源
最近更新 更多