寻找一个可以翻转sprintf()函数输出的算法

5
我正在研究一个需要解析日志文件的项目。我正在寻找一种快速算法,它可以将像这样的消息分组:

在P1处的温度为35华氏度。

在P1处的温度为40华氏度。

在P3处的温度为35华氏度。

记录器停止。

记录器启动。

在P1处的温度为40华氏度。

并输出类似printf()的内容:

"The temperature at P%d is %dF.", Int1, Int2" 
{(1,35), (1, 40), (3, 35), (1,40)}

该算法需要足够通用,能够识别消息组中几乎任何数据负载。

我尝试搜索这种技术,但我甚至不知道正确的术语去搜索。

10个回答

12

我认为你可能忽视了fscanf()和sscanf()。它们是fprintf()和sprintf()的相反操作。


6

概述:

一个天真的算法以每列的方式跟踪单词的频率,其中可以假设每一行都可以用分隔符分成多列。

示例输入:

The dog jumped over the moon
The cat jumped over the moon
The moon jumped over the moon
The car jumped over the moon

频率:

Column 1: {The: 4}
Column 2: {car: 1, cat: 1, dog: 1, moon: 1}
Column 3: {jumped: 4}
Column 4: {over: 4}
Column 5: {the: 4}
Column 6: {moon: 4}

我们可以根据字段的总数进一步分组,但在这个简单而方便的例子中,我们只使用了固定数量的字段(6个)。
下一步是迭代生成这些频率列表的行,让我们以第一个例子为例:
1. “The”:符合某些模糊标准,算法决定它必须是静态的。 2. “dog”:根据剩余的频率列表似乎不是静态的,因此它必须是动态的文本。我们循环几个预定义的正则表达式,得出`/[a-z]+/i`。 3. “over”:与#1相同;它是静态的,所以保持原样。 4. “the”:与#1相同;它是静态的,所以保持原样。 5. “moon”:与#1相同;它是静态的,所以保持原样。
因此,仅从第一行开始,我们就可以组合出以下正则表达式:
/The ([a-z]+?) jumps over the moon/

考虑因素:
  • 显然,第一遍可以选择扫描部分或整个文档,只要您确信频率列表将是整个数据的足够抽样。

  • 假阳性可能会影响结果,过滤算法(手势)将提供静态和动态字段之间最佳阈值,或进行人工后处理。

  • 总体想法可能是一个好想法,但实际实现肯定会影响此算法的速度和效率。


3
感谢所有出色的建议。克里斯说得对,我正在寻找一种通用的解决方案来规范任何类型的文本。问题的解决方法在于动态地在两个或更多相似的字符串中找到模式。就像根据前两个元素预测集合中的下一个元素一样:
1: 珠穆朗玛峰高30000英尺
2: K2高28000英尺
=>什么是模式?
=>答案:
[name]高[number]英尺
现在文本文件可以有数百万行和数千个模式。我希望能够非常快速地解析文件,找到模式并收集与每个模式相关的数据集。
我考虑创建一些高级语义哈希来表示消息字符串中的模式。我将使用标记器,并为每个标记类型指定特定的“权重”。然后,我将分组哈希并评估它们的相似性。完成分组后,我将收集数据集。
我希望我不必重新发明轮子,而是可以重复使用已经存在的东西。
克劳斯

2

这取决于你想做什么,如果你的目标是快速生成sprintf()输入,那么这个方法可以使用。如果你想解析数据,也许正则表达式也可以完成。


1

你不可能找到一个工具,它可以简单地接受任意输入,猜测你想要的数据,并产生你想要的输出。对我来说,这听起来像是强人工智能。

即使只是识别数字,也会变得非常麻烦。例如,“123.456”是一个数字还是两个数字?“123,456”呢?“35F”是一个十进制数和一个“F”,还是16进制值0x35F?你必须构建一个按照你需要的方式进行解析的东西。你可以使用正则表达式完成这一点,或者你可以使用 sscanf ,或者你可以用其他方式,但你必须编写一些自定义代码。

然而,通过基本的正则表达式,你可以自己完成这个任务。虽然不会是魔法,但也不需要太多的工作量。像这样的 Perl 代码可以解析你感兴趣的行并将它们合并:

my @vals = ();
while (defined(my $line = <>))
{
    if ($line =~ /The temperature at P(\d*) is (\d*)F./)
    {
        push(@vals, "($1,$2)");
    }
}
print "The temperature at P%d is %dF. {";
for (my $i = 0; $i < @vals; $i++)
{
    print $vals[$i];
    if ($i < @vals - 1)
    {
        print ",";
    }
}
print "}\n";

这个的输出是:

The temperature at P%d is %dF. {(1,35),(1,40),(3,35),(1,40)}

对于每种需要解析的行类型,您可以执行类似的操作。您甚至可以从文件中读取这些正则表达式,而不是自定义编码每个表达式。


1

我不知道有什么具体的工具可以做到这一点。当我遇到类似的问题需要解决时,我会尝试猜测正则表达式来匹配行。

然后我处理文件并仅显示未匹配的行。如果一行没有匹配成功,那么就意味着模式是错误的,应该进行调整或添加另一个模式。

经过大约一个小时的工作,我成功地找到了大约20个模式来匹配10000多行。

在您的情况下,您可以首先“猜测”一个模式是"P [1-3]处的温度为[0-9]{2}F。"。如果您重新处理文件并删除任何匹配的行,则只剩下:

记录器停止。

记录器启动。

然后您可以使用"Logger (.+)."与其匹配。

然后您可以完善模式并找到新的模式来匹配整个日志。


0

http://www.logparser.com 转到一个似乎相当活跃的 IIS 论坛。这是 Gabriele Giuseppini 的“Log Parser Toolkit”的官方网站。虽然我实际上从未使用过这个工具,但我在 Amazon Marketplace 上购买了一本便宜的书 - 现在一本只要 16 美元。对于翻阅页面来说,没有什么比纸质书更好的了。

浏览这个论坛时,我之前没有听说过“MS Log Parser 的新 GUI 工具 Log Parser Lizard”,位于 http://www.lizardl.com/

当然,关键问题是你的 GRAMMAR 复杂性。使用任何常用术语中的日志分析器,您需要确切地知道您正在扫描什么,您可以写出一个 BNF。多年前,我参加了一门基于 Aho 和 Ullman 的“龙书”教程,彻底理解的 LALR 技术可以为您提供最佳速度,当然前提是您拥有该 CFG。

另一方面,似乎您可能会寻找某种类似 AI 的东西,这完全是不同层次的复杂性。


0

@John:我认为这个问题涉及到一种能够识别日志文件中模式并自动“猜测”适当格式字符串和数据的算法。 *scanf系列本身无法完成此任务, 它只能在首次识别模式后提供帮助。


0

@Derek Park:即使是强大的人工智能也不能确定它有正确的答案。

也许可以使用一些类似于压缩的机制:

  1. 查找大型频繁子字符串
  2. 查找大型频繁子字符串模式。(即 [pattern:1] [junk] [pattern:2])

另一个要考虑的问题可能是按 编辑距离 分组行。将相似的行分组应该将问题分成每组一个模式的块。

实际上,如果你成功地写出了这个工具,让全世界都知道,我想我们很多人都会喜欢这个工具!


0

@Anders

即使是强人工智能也不能确定它有正确的答案。

我认为足够强大的人工智能通常可以从上下文中找到正确的答案。例如,强人工智能可以识别出这种情况下的“35F”是温度而不是十六进制数。当然,还有一些情况即使是强人工智能也无法回答。但这些情况对于人类来说也是一样的(假设非常强大的人工智能)。

当然,由于我们没有强人工智能,所以这并不重要。 :)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接