【问题标题】:Parsing poorly formatted Log files?解析格式不佳的日志文件?
【发布时间】:2011-04-26 11:13:10
【问题描述】:

我正在处理一些非常格式很差的日志文件,列分隔符是一个(经常)出现在字段中的项目,它不是逃脱了。例如:

sam,male,september,brown,blue,i like cats, and i like dogs

地点:

name,gender,month,hair,eyes,about

如您所见,about 包含列分隔符,这意味着分隔符的单个解析将不起作用,因为它会将 about me 分成两个单独的列。现在想象一下这个聊天系统......你可以想象我确定的问题。

那么,理论上解决这个问题的最佳方法是什么?我不是在寻找特定于语言的实现,而是更多指向正确方向的一般指针,或者关于其他人如何解决它的一些想法...... 没有手动进行。

编辑:

我应该澄清一下,我的 实际 日志处于更糟糕的状态。这些字段到处都是分隔符,我找不到任何模式。

【问题讨论】:

  • 您能解释一下所选答案如何解决您的问题吗?我很想知道...

标签: parsing theory logging


【解决方案1】:

如果只有最后一列有未转义的逗号,那么大多数语言的字符串拆分实现可以限制拆分的数量,例如在 Python 中s.split(',',5)

如果您想将文件解析为 CSV(逗号分隔值)解析器,那么我认为最好的方法是运行一个修复程序,在将其传递给 csv 解析器之前进行适当的转义。

【讨论】:

  • 我应该提到这不是我的实际日志,它更糟糕,这只是一个基本示例。我在这些中找不到任何可靠的模式。
  • @criticsquid:你能给出一个实际日志的小样本吗?尤其是最坏的情况。
【解决方案2】:

我想您可以对数据类型做出某些假设。比如gendermonthhaireyes 有一个值域,然后验证它。

除了about 和可能name 之外的所有字段都不包含逗号也是有道理的,所以也许您可以贪婪地解析,使前 5 个或 6 个逗号充当分隔符,其他所有内容都是其中的一部分about。必要时再次验证。

【讨论】:

    【解决方案3】:

    如果不使用转义,可能无法完美解析它们。

    Lie Ryan 指出,如果只有最后一列可以包含这些值,那么您可以在那里选择。

    如果不是这样,是否有任何列可以保证您始终缺少未转义的保留字符?另外,是否有任何列可以保证您始终只有一组特定的值?

    如果其中任何一个为真,您可以先识别这些字段,然后将其他所有内容分开以将其从那里拆分出来。

    我必须知道更多关于你的信息的细节才能走得更远。

    【讨论】:

      【解决方案4】:

      您可以尝试以下两个想法:

      • 长度/格式模式 - 我认为您可以识别文件各个列中的一些模式。例如,某些列中的值可能更短,而某些列中的值可能更短。某些列中的值通常是数字或来自一组有限的值(例如月份),或者至少经常包含一些子字符串。

        当您可以识别这些模式时(基于从正确分隔项目的项目计算的统计数据),那么您应该创建使用这些模式来猜测应该忽略哪些分隔符的算法(例如,当列短于预期时) .

      • 语法规则 - 受您的示例启发的另一个想法 - 没有转义的逗号通常后跟一些字符串(例如单词“and”或“about”?)如果是,您可以使用这个信息来猜测哪些分隔符应该被转义。

      最后,如果这些临时技术都不能解决您的问题,那么您可以使用一些繁重的统计数据来进行估计。有一些机器学习框架可以为你做大量的统计,但这仍然是一个相当复杂的问题。例如,在 .NET 上,您可以使用来自 Microsoft Research 的 Infer.NET

      【讨论】:

        【解决方案5】:

        如果可能的话,我建议做的一件事是在每个数据记录中保留一些内容,表明所做的假设(可能保留原始字符串),以便在发现记录有问题时正确的数据希望可以重建(如果没有别的,可以通过手工检查)。

        【讨论】:

          【解决方案6】:

          如果第 6 列始终是最后一列,并且始终未转义,则 perl 的这一点应该可以解决问题:

          $file = '/path/to/my/log.txt';
          open(LOG, $file);
          @lines = <LOG>;
          
          foreach $line (@lines)
          {
              chomp($line);
              if ($line =~ /([A-Za-z0-9_]+)\,([A-Za-z0-9_]+)\,([A-Za-z0-9_]+)\,([A-Za-z0-9_]+)\,([A-Za-z0-9_]+)\,([A-Za-z0-9_\, ]+)/)
              {
                  print "Name:         $1\n";
                  print "Gender:       $2\n";
                  print "Month:        $3\n";
                  print "Color #1:     $4\n";
                  print "Color #2:     $5\n";
                  print "Random Text:  $6\n";
              }
          }
          
          close(LOG)
          

          【讨论】:

            【解决方案7】:

            您的日志是模棱两可的:您无法确定要做出许多可能的解释中的哪一个。处理不确定性是概率论的工作。一个自然的工具是probabilistic context-free grammar——有一些算法可以找到最可能的解析。 (虽然我用这种统计方法做过更简单的工作,但我自己没有机会使用过。Peter Norvig 的spelling-corrector article 详细介绍了一个这样的例子。)

            对于这个特殊的简化问题:您可能会列举所有可能的方法来将一条线分成 N 个部分(您已经知道 N 的期望值),根据某个模型计算每个部分的概率,然后选择最佳答案。

            (处理删除了区别的数据的另一个示例:我有一个来自 50 万张 Flickr 照片的标签数据集。标签来自他们的 API,所有单词与空格一起被挤压出来。我计算出最有可能使用来自互联网摄影网站的词频列表,加上 this SO answer 之类的代码。)

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2012-04-03
              • 1970-01-01
              • 2014-03-02
              • 1970-01-01
              • 1970-01-01
              • 2016-02-14
              • 2010-10-17
              • 2016-01-09
              相关资源
              最近更新 更多