寻找可反转sprintf()函数输出的算法
我正在一个需要解析日志文件的项目中。我正在寻找一种快速的算法,该算法可以接收如下组消息:
The temperature at P1 is 35F. The temperature at P1 is 40F. The temperature at P3 is 35F. Logger stopped. Logger started. The temperature at P1 is 40F.
并以printf()形式输出:
"The temperature at P%d is %dF.", Int1, Int2" {(1,35), (1, 40), (3, 35), (1,40)}
该算法必须足够通用,才能识别消息组中的几乎所有数据负载。
我曾尝试搜索这种技术,但我什至不知道要搜索的正确术语。
解决方案
回答
我认为我们可能会忽略并错过了fscanf()和sscanf()。与fprintf()和sprintf()相反。
回答
如果目标是快速生成sprintf()输入,那么这取决于我们要执行的操作。如果我们尝试解析数据,也许正则表达式也可以。
回答
@约翰:我认为这个问题与一种算法有关,该算法实际上可以识别日志文件中的模式,并自动"猜测"相应的格式字符串和数据。 * scanf
系列不能单独做到这一点,只有首先识别出模式之后,它才能提供帮助。
回答
我们将不会找到可以简单地接受任意输入,猜测所需的数据并生成所需输出的工具。在我看来,这听起来像是强大的AI。
产生这样的东西,即使只是为了识别数字,也会变得很毛茸茸。例如," 123.456"是一个数字还是两个?这个" 123,456"怎么样? " 35F"是一个十进制数和一个" F"还是十六进制值0x35F?我们将必须构建一些可以按照我们需要的方式进行解析的东西。我们可以使用正则表达式来执行此操作,也可以使用sscanf来执行此操作,也可以使用其他方式来执行此操作,但是我们将不得不编写一些自定义的内容。
但是,使用基本的正则表达式,我们可以自己执行此操作。这不会是魔术,但是它不需要那么多工作。这样的事情将解析我们感兴趣的行并将其合并(Perl):
my @vals = (); while (defined(my $line = <>)) { if ($line =~ /The temperature at P(\d*) is (\d*)F./) { push(@vals, "(,)"); } } 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";
这个的输出是L
The temperature at P%d is %dF. {(1,35),(1,40),(3,35),(1,40)}
我们可以对每种需要解析的行类型执行类似的操作。我们甚至可以从文件中读取这些正则表达式,而不必对每个正则表达式进行自定义编码。
回答
感谢我们提出的所有宝贵建议。
克里斯,是的。我正在寻找一种规范化任何类型文本的通用解决方案。问题的解决可以归结为动态地找到两个或者更多相似字符串中的模式。
基于前两个,几乎就像预测集合中的下一个元素:
1:珠穆朗玛峰30000英尺高
2:K2高28000英尺
=>模式是什么?
=>回答:
[名字]是[数字]英尺高
现在,文本文件可以具有数百万行和数千个模式。我想非常非常快速地解析文件,找到模式并收集与每个模式相关的数据集。
我考虑过要创建一些高级语义哈希来表示消息字符串中的模式。
我将使用令牌生成器,并为每个令牌类型指定一个特定的"权重"。
然后,我将对哈希进行分组并评估其相似性。分组完成后,我将收集数据集。
我希望我不必重新发明轮子,而是可以重用已经存在的东西。
克劳斯
回答
我不知道有什么特定的工具可以做到这一点。当我遇到类似问题要解决时,我所做的就是尝试猜测正则表达式以匹配行。
然后,我处理了文件并仅显示不匹配的行。如果一行不匹配,则表示该模式错误,应进行调整或者添加其他模式。
经过大约一个小时的工作,我成功找到了〜20个模式以匹配10000+行。
对于情况,我们可以首先"猜测"一个模式是"" P [1-3]处的温度为[0-9] {2} F。"。如果重新处理文件,删除任何匹配的行,它将保留" only":
Logger stopped. Logger started.
然后,我们可以将其与"记录器(。+)"进行匹配。
然后,我们可以优化模式并找到新的模式以匹配整个日志。
回答
概述:
天真!该算法以每列的方式跟踪单词的频率,在这种情况下,我们可以假设每一行都可以用定界符分隔成几列。
输入示例:
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)。
下一步是遍历生成这些频率列表的行,因此让我们来看第一个示例。
- The:满足一些手工波浪标准,并且算法确定它必须是静态的。
- dog:根据频率列表的其余部分来看,它似乎不是静态的,因此与静态文本相反,它必须是动态的。我们遍历一些预定义的正则表达式,并给出
/ [a-z] + / i
。 - 超过:与#1相同;它是静态的,因此保持原样。
- 与#1相同;它是静态的,因此保持原样。
- 月球:与#1交易相同;它是静态的,因此保持原样。
因此,仅需通过第一行,我们就可以将以下正则表达式组合在一起:
/The ([a-z]+?) jumps over the moon/
注意事项:
- 显然,只要可以确信频率列表将是对整个数据的足够采样,就可以选择扫描部分或者整个文档进行第一次扫描。
- 误报可能会渗入结果,这将取决于过滤算法(手动波动),以在静态和动态场之间或者某些人工后处理之间提供最佳阈值。
- 总体思路可能是一个好主意,但是实际的实现肯定会影响该算法的速度和效率。
回答
@Derek Park:好吧,即使是强大的AI也无法确定它是否有正确的答案。
也许可以使用一些类似压缩的机制:
- 查找频繁的大子串
- 查找频繁的大子串模式。 (即[pattern:1] [junk] [pattern:2])
另一个要考虑的项目可能是按编辑距离对行进行分组。对相似的行进行分组应该将问题分成每组一个模式的大块。
实际上,如果我们设法编写此文件,请让全世界知道,我想我们很多人都希望使用此工具!
回答
@安德斯
Well, even a strong AI couldn't be sure it had the right answer.
我以为足够强大的AI通常可以从上下文中找出正确的答案。例如在这种情况下,强大的AI可以识别出" 35F"是温度,而不是十六进制数。肯定在某些情况下,即使强大的AI也无法回答。但是,在那些情况下,人类将无法回答(假设AI非常强)。
当然,这并不重要,因为我们没有强大的AI。 :)