是否存在按模式(正则表达式)提供查找的数据结构?

时间:2013-08-07 19:51:11

标签: c# .net regex data-structures

我已经多次遇到过这种情况:有些文本可能会匹配多种模式,你想根据它的模式做一些具体的事情。

在过去,我总是只使用正则表达式列表并迭代直到找到匹配。

我想知道的是,是否有更高效的数据结构。例如,如果我使用C#,带有正则表达式键的字典。

我意识到如果模式都是前缀或后缀,那么像Trie这样的东西就会有意义。但是,我不清楚这是否适用于一般情况。

在我看来,围绕关键碰撞可能会有些含糊不清;例如,如果某些文本匹配多个模式,应该返回什么? (我认为在这种情况下可能会有一个非确定性结果;但只要行为记录在案,我就可以了。)

无论如何,在.NET或其他地方是否存在这样的数据结构?

3 个答案:

答案 0 :(得分:4)

fgrep工具正是您所说的:将文本与多个正则表达式进行匹配。我的理解是原始版本使用了与Aho-Corasick string matching algorithm非常相似的东西来在一次传递中搜索多个正则表达式。基本上,它创建了一个DFA并通过它。

我不知道fgrep的.NET实现。如果你找到一个,我当然有兴趣听听它。

您可以追踪fgrep源代码(谷歌为它,有很多来源),看看它是如何实现的。

或者,您可以将程序shell发送到fgrep。或者也许创建一个C ++ DLL,它有一个可以从C#程序调用的fgrep入口点。

如果您的多个模式是常量字符串(即非正则表达式),那么您可能对我的C# implementation of the Aho-Corasick algorithm感兴趣。

答案 1 :(得分:3)

让我们假设这些正则表达式是真正规则的。然后可以将每个Nondeterministic Finite Automaton转换为convertedDeterministic Finite Automaton,可以在输入长度的O(n)时间内进行评估。

但它没有解决同时匹配多个正则表达式的问题。我们可以通过创建一个如下所示的正则表达式来完成此操作:(regexp1|regexp2|...),并将 转换为单个NFA / DFA。在自动机的分支中添加一些检测,以跟踪哪个特定的正则表达式产生了与输入匹配的路径,并且您已经得到了匹配器,仍然是输入字符串长度的O(n)。

此技术不支持任何使该语言非常规的“正则表达式”功能such as backreferences

另一个缺点是产生的DFA可能很大。也可以直接评估NFA,这可能更慢,但具有更好的记忆行为。


实际上,在代码中表达这个想法也很容易,而不用担心自动机的东西。只需使用匹配的组:

combined_regexp = (regexp1)|(regexp2)|...

在评估时,只需查看与输入匹配的组。

请记住,大多数正则表达式实现/库在某些极端情况下具有相当差的行为,在这些情况下,它们可以采用指数时间来编译或匹配正则表达式。我不确定实际上有多少问题。谷歌的RE2图书馆是专门设计的,不会有这种病态行为,但可能还有其他图书馆。

另一个问题可能是,除非您的正则表达式实现专门宣传O(n)行为,否则它可能只是依次尝试每个备选方案。在这种情况下,这种方法不会给你任何东西。

答案 2 :(得分:0)

几年前,我基于确定性有限状态机实现了一个正则表达式搜索引擎,非常类似于托马斯在他的回答中所描述的。它将正则表达式键和值列表编译为单个有限状态自动机,该自动机在其终端状态中引用已定义类型的对象(例如,RegexTrie引用终端状态的字符串)。

可在此处获取实施:https://bitbucket.org/tjnieminen/regexkeytrie

通过维护机器的路径列表来执行标准搜索。每个活动路径都针对搜索文本的每个字符进行提前,并且只要达到终端状态就会记录匹配。为源文本的每个字符添加从机器根开始的新路径(这允许子字符串匹配),并且从路径列表中删除停止在非终端状态的路径。

通常最好根据任务自定义处理。例如,如果使用引擎进行正则表达式替换,最好在遍历期间生成编辑后的文本(如传感器),而不是使用返回的匹配执行查找和替换操作。

我已经根据正常的.Net正则表达式对实现进行了基准测试,并且它似乎在它应该的场景中做得更好,即结合使用大量正则表达式和长文本进行搜索。

实现尚未经过全面测试,因此可能会留下一些错误,并且使用复杂的正则表达式可能相当容易耗尽内存(或者它们可能需要永远编译)。但由于目前没有类似的东西,对于寻找它所提供的性能特征的人来说,它可能是一个有用的起点。