Parsing 解析格式不良的日志文件?

Parsing 解析格式不良的日志文件?,parsing,theory,logging,Parsing,Theory,Logging,我正在处理一些格式非常糟糕的日志文件,列分隔符是一个(经常)出现在字段中的项,并且不会转义。例如: sam,male,september,brown,blue,i like cats, and i like dogs 其中: name,gender,month,hair,eyes,about 如您所见,about包含列分隔符,这意味着分隔符的单个解析将不起作用,因为它将about me分隔为两个单独的列。现在想象一下这是一个聊天系统。。。我相信你可以想象这些问题 那么,理论上解决这个问题的最

我正在处理一些格式非常糟糕的日志文件,列分隔符是一个(经常)出现在字段中的项,并且不会转义。例如:

sam,male,september,brown,blue,i like cats, and i like dogs
其中:

name,gender,month,hair,eyes,about
如您所见,about包含列分隔符,这意味着分隔符的单个解析将不起作用,因为它将about me分隔为两个单独的列。现在想象一下这是一个聊天系统。。。我相信你可以想象这些问题

那么,理论上解决这个问题的最佳方法是什么?我不是在寻找一个特定于语言的实现,而是一个指向正确方向的通用指针,或者关于其他人如何解决它的一些想法。。。不需要手动操作

编辑:


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

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


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

我想您可以对数据类型做出某些假设。像
gender
month
hair
、和
eyes
都有一个值域,然后验证这一点


除了
关于
名称
之外的所有字段都不包含逗号,因此您可以贪婪地解析,使前5或6个逗号充当分隔符,其他所有内容都是
关于
的一部分。如有必要,请再次验证。

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

Lie Ryan指出,如果只有最后一列可以有这些值,那么您就有了一个选项

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

如果其中一个是真的,那么您可以首先识别这些字段,然后将其他所有字段分离出来,从中分割出来


我必须了解有关您的信息的更多细节才能进一步了解。

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

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

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

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


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

如果可能的话,我建议您在每个数据记录中保留一些指示所做假设的内容(可能保留原始字符串),这样,如果发现某个记录有错,就可以重建正确的数据(如果没有其他内容,则手动检查)。

如果第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)
$file='/path/to/my/log.txt';
打开(日志文件);
@行=;
foreach$行(@行)
{
chomp($line);
如果($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+])/)
{
打印“名称:$1\n”;
打印“性别:$2\n”;
打印“月份:$3\n”;
打印“颜色1:$4\n”;
打印“颜色2:$5\n”;
打印“随机文本:$6\n”;
}
}
关闭(日志)

您的日志模棱两可:您无法确定要对许多可能的解释中的哪一种进行解释。处理不确定性是概率论的一项工作。那么,一个自然的工具就是——有一些算法可以找到最可能的解析。(虽然我用这种统计方法做过更简单的工作,但我自己也没有机会使用这种方法。Peter Norvig的文章就这样一个例子进行了详细的实践。)

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


(另一个处理去除差异的数据的例子是:我有一个50万张Flickr照片中的标签数据集。这些标签来自API,所有的单词都是rungether,空格都被压扁了。我使用互联网摄影网站上的词频表,加上类似的代码,计算出最可能的单词边界。)

我应该提到,这不是我的实际日志,更糟糕的是,这只是一个基本的例子。我在这些日志中找不到任何可靠的模式。@criticsquid:你能给出一个实际日志的小样本吗?特别是最坏的情况。你能解释一下所选答案是如何解决你的问题的吗?我很想知道。。。