简而言之
看来,解决您问题的快速方法是定义一个REGEX或FSA(有限状态自动机),该功能可以识别所有可能的文档开头(允许出现误报,但实际上与文档不符)。然后,您可以非常快速地在输入中运行它,以识别下一个可以以很少的错误开始文档的位置。它可能会导致一些错误的文档开始位置,但是解析器将识别它们并将其放弃。
因此,有限状态自动机可能是您正在寻找的解析器名称。:)
问题
总是很难理解一个实际问题,尤其是当词汇可能有很多解释时。词法分析林是为具有多个分析树的模棱两可的句子的上下文无关(CF)语法分析而创造的(afaik)。可以将其概括为解析句子的格点或其他类型的语法。因此,有关Earley,GLR,Marpa和派生解析器(还有很多其他解析器)的所有答案在这种情况下均不相关。
但这显然不是您要考虑的。您想解析一个唯一字符串,该字符串是一系列明确的文档,并为每个或某种结构化表示获取一个解析树,因为您并未真正说出文档的语法是如何定义的,从何而来正式的语言观点。您所拥有的是一种算法和表格,它们将从文档的开头开始进行解析。随它吧。
实际的问题是您的文档流包含大量垃圾,这些垃圾将文档分隔开。而且看来您的困难在于足够快地扫描此垃圾。您当前的技术是从头开始,尝试从第一个字符开始扫描,并在出现故障时跳到下一个字符重新开始,直到扫描完整个文档为止。然后,从刚扫描的文档后的第一个字符开始重复说明。
这也是@amon在回答第二部分中建议的解决方案。
这可能不是一个非常快速的解决方案(我无法测试),因为解析器的代码不太可能被优化为在文档的开头非常有效地启动。在正常使用中,它只会执行一次,因此从优化的角度来看,它不是热点。因此,您对此解决方案的满意程度并不奇怪。
因此,您真正需要的是一种可以快速找到以大量垃圾开头的文档开头的算法。您很幸运:这样的算法确实存在。而且我敢肯定,您知道的:这称为搜索REGEX。
简单的解决方案
您要做的是分析文档的规范,以查找这些文档的开始方式。我无法确切告诉您如何进行,因为我不确定它们的语法规范是如何正式组织的。可能它们都以有限列表中的某个单词开头,可能还混有一些标点符号或数字。那是你要检查的。
您要做的是定义一个有限状态自动机(FSA),或者等效地,对于大多数程序员来说,一个正则表达式(REGEX)可以识别文档的前几个字符:越多越好,但是不一定要很大(可能会占用时间和空间)。从文档的说明中应该比较容易做到这一点,并且可以使用读取文档说明的程序自动完成此操作。
生成正则表达式后,可以在输入流上运行它,以非常快速地到达第一个(或下一个)文档的开头,如下所示:
我假设:
- docstart
是一个与所有文档开头匹配的正则表达式
- search(regex, stream)
是一个搜索的stream
子字符串的函数regex
。返回时,该流将从第一个匹配子字符串的开头开始减少到其后缀子流,或者减少到找不到匹配项的空流。
- parse(stream)
尝试从流的开头(剩下的内容)开始解析文档,然后以任何格式返回解析树,否则将失败。当返回时,该流从紧接在解析文档结束之后的位置开始,被缩减为其后缀子流。如果解析失败,它将调用异常。
forest = empty_forest
search(docstart, stream)
while stream is not empty:
try:
forest = forest + parse(stream)
except
remove first character from stream
search(docstart, stream)
请注意,必须删除第一个字符,以便下一次搜索不会再次找到相同的匹配项。
当然,缩短流是一幅图像。它可能只是流上的索引。
最后一点是,您的正则表达式不需要太准确,只要它能识别所有开头即可。如果它偶尔识别出不能作为文档开头的字符串(误报),则唯一的代价就是对解析器进行一次无用调用的代价。
因此,如果有用的话,可能有助于简化正则表达式。
关于更快解决方案的可能性
上述解决方案在大多数情况下应该可以很好地工作。但是,如果您确实要处理大量垃圾和TB级文件,则可能还有其他算法运行速度更快。
这个想法源于Boyer-Moore字符串搜索算法。该算法可以非常快速地在流中搜索单个字符串,因为它使用了对字符串的结构分析,从而跳过了大部分流的读取,甚至不看片段就跳过了片段。对于单个字符串,这是最快的搜索算法。
Thr的困难在于,它要适应搜索正则表达式而不是单个字符串,这看起来非常微妙,并且可能无法正常工作,具体取决于您考虑的正则表达式的功能。这可能反过来取决于您正在解析的文档的语法。但是不要对此太信任我,因为我没有时间仔细阅读发现的文档。
我要给您留下我在网上找到的一个或两个指针,其中包括一个显然是参考性的研究论文,但只有在您遇到严重的性能问题时,才应将其视为更具推测性,可能是研究性的指针。而且可能没有架子程序可以做到这一点。