高效地查询一个字符串与多个正则表达式的匹配

55
假设我有10,000个正则表达式和一个字符串,我想找出它是否与它们中的任何一个匹配,并获取所有匹配结果。传统的方法是逐个查询该字符串对所有正则表达式进行匹配。是否有更快、更高效的方法呢?
编辑: 我尝试使用DFA(lex)进行替换 这里的问题是它只会给您一个单一的模式。如果我有一个字符串“hello”和模式“[H|h]ello”和“.{0,20}ello”,DFA只会匹配其中一个,但我希望两个都匹配上。

通常情况下,人们会尽量避免歧义,因此有一些标准可以选择匹配的模式。通常选择最长的最左匹配。如果您有这个需求,您可能需要自己编写一些内容。 - Remo.D
1
在回答相关问题时发现了这个。由于这个问题是在'08年提出的,我已经发布了一个开源Java库,您可以使用它来构建DFA,如果需要,它将为您提供所有匹配的表达式:http://mtimmerm.github.io/dfalex/。 - Matt Timmermans
18个回答

3

如果您只需要知道哪些正则表达式匹配,我建议使用英特尔的Hyperscan。它是为此目的而构建的。如果您需要执行的操作更加复杂,您也可以使用ragel。尽管它只产生一个DFA并且可能会产生许多状态,从而导致非常大的可执行程序。Hyperscan采用混合NFA / DFA /自定义方法进行匹配,能够很好地处理大量表达式。


2
我认为这需要一个真正的解析器。一种中间方法可能是解析表达式语法(PEG)。它是一种更高级的模式匹配抽象,其中一个特点是你可以定义整个语法而不是单个模式。有一些高性能的实现方式,通过将你的语法编译成字节码并在专门的虚拟机中运行来工作。
免责声明:我知道的唯一一种是LPEG,它是Lua的一个库,对于我来说理解基本概念并不容易。

3
PEG比所需的功能强大(但速度较慢)。一组正则语言的并集是正则的,也就是说,一个简单的NFA就足够了。 - Eamon Nerbonne

0

我几乎建议编写一个“从内到外”的正则表达式引擎 - 其中“目标”是正则表达式,“项”是字符串。

然而,看起来你的解决方案是迭代地尝试每个,这将更容易。


0

你可以将正则表达式编译成混合DFA/Bucchi自动机,每当BA进入接受状态时,您就会标记哪个正则表达式规则“命中”。

Bucchi对此有些过度,但修改DFA工作方式可能会奏效。


0

我使用 Ragel 并带有一个离开动作:

action hello {...}
action ello {...}
action ello2 {...}
main := /[Hh]ello/  % hello |
        /.+ello/ % ello |
        any{0,20} "ello"  % ello2 ;

字符串 "hello" 会调用 action hello 块中的代码,然后是 action ello 块和最后是 action ello2 块。

它们的正则表达式相当有限,机器语言更受青睐,您示例中的大括号只适用于更通用的语言。


-1

目前看来最快的方法是像这样做(代码为 C#):

public static List<Regex> FindAllMatches(string s, List<Regex> regexes)
{
    List<Regex> matches = new List<Regex>();
    foreach (Regex r in regexes)
    {
        if (r.IsMatch(string))
        {
            matches.Add(r);
        }
    }
    return matches;
}

哦,你是指最快的代码?那我不知道了...


1
过早优化啰嗦啰嗦...看看你最简单的解决方案有多慢,尤其是考虑到实现它的代码是多么简单。 - ijw
那么,您认为应该采取什么措施来提高效率呢? - RCIX
1
如果你正在测试一万个正则表达式,那么速度会非常慢。你需要一种方法来合并树以获得单次解析器。 - Sridhar Iyer

-1

尝试将它们组合成一个大的正则表达式?


那肯定值得一试 - 希望正则表达式编译器能够优化一些东西... - Mark Bessey
一般来说,这通常会慢得多。 - Jimmy
这实际上是一个非常合理和快速的解决方案 - 如果您正在使用基于直接NFA模拟的正则表达式。不幸的是,大多数正则表达式实现并不是这样的 - 因此在实践中无法工作。 - Eamon Nerbonne

-1

我认为简短的回答是肯定的,计算机科学中已经有一种方法可以实现这种功能,只是我现在想不起来它叫什么了。

简单地说,你可能会发现你的正则表达式解释器已经能够有效地处理所有这些内容(用 | 连接在一起),或者你可以找到一个能够做到这一点的解释器。如果不行,那么现在就是时候查找字符串匹配和搜索算法了。


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