如果我有一些未知数量的正则表达式(零或更多,希望少于几千),那么搜索与给定字符串匹配的正则表达式的有效方法是什么?
我应该使用哪种容器,算法和/或数据结构?这是不同的,如果我想找到唯一匹配的正则表达式比我想要的所有正则表达式匹配?这些不同只是想知道有多少匹配?
让我换一种方式,让我们假设我有一个用户输入任意字符串,我有一些容器的正则表达式。我可以按照我选择的任何方式设计容器,并以我选择的任何方式进行搜索。如果我想要一个与该集合中的用户输入匹配的所有正则表达式列表,我该怎么办?如果我只是想知道有多少匹配怎么办?如果我只是想确保比赛的独特性怎么办?
答案 0 :(得分:1)
如果在尝试匹配字符串之前可以对正则表达式进行一些预计算,那么可以将所有字符串的并集转换为DFA,它可以同时将字符串与所有字符串进行匹配。 / p>
请参阅:https://en.wikipedia.org/wiki/Deterministic_finite_automaton
这种方法经常用于解析器和编译器中的词法分析(标记化)。 DFA的好处在于它的速度(快速)是相同的,无论你投入多少正则数或它们有多复杂。
这不是那么容易,但周围有工具。如果你在Java工作,那么我有一个你可以使用的开源项目:http://mtimmerm.github.io/dfalex/。要回答您的其他问题,您可以根据需要获取所有匹配的正则数据集。
如果您对自己如何操作感兴趣,该过程通常包括使用Thompson的构造(https://en.wikipedia.org/wiki/Nondeterministic_finite_automaton)将正则表达式转换为NFA(https://en.wikipedia.org/wiki/Thompson%27s_construction),然后转换NFA使用子集构造(https://en.wikipedia.org/wiki/Powerset_construction)进入DFA,然后通常使用Hopcroft算法(https://en.wikipedia.org/wiki/DFA_minimization)最小化DFA
有很多优化和技巧的空间。
祝你好运!
P.S。我应该注意几件事情:1)你通常不能从具有反向引用的正则表达式中生成DFA。 2)从理论上讲,DFA可能呈指数级增长。这几乎不会偶然发生,但如果您的正则表达式是由潜在恶意的人输入的,那么您将不得不对这种可能性做些什么。
答案 1 :(得分:0)
答案 2 :(得分:0)
除非没有人在几天内击败它,否则我不会将自己的答案标记为答案。
到目前为止,我唯一有价值的想法是将正则表达式添加到容器内的两个堆中的一个堆中。
在每一个正则表达式中使用一些通配符,字符类或其他任何使其偏离传统字符串的正则表达式。我将其称为 RegexPile 。
进入另一堆所有正则字符串或字符串可转换为字符串。因为字符串很容易匹配并且算法很好理解,我可以说这个堆将是和有序容器并将被排序,并且在其中查找字符串与二进制搜索是微不足道的。我将其称为 SortedStringArray 。
天真地,我可以线性搜索 RegexPile 并在 SortedStringArray 上进行二进制搜索。这至少允许我跳过一些比较并且在时间或空间方面花费很少,但也没有太多真正的优化。
它在计算上是相似的,但如果我做这样的事情,我想我会在 RegexPile 中为每个正则表达式(或每组小规模的正则表达式)启动一个线程。我的想法是,任何给定的正则表达式都可以采取无限量,因为正则表达式可以做到这一点。然后,如果任何线程花费太长时间,我可能会因超时而失败,并提前终止所有线程。我还认为大多数人会在第一个字符上失败,这意味着一旦检查到第一个字符,大多数线程就会消失。由于现在大多数系统都提供廉价的写时复制线程,这个线程产生应该足够便宜,以至于许多线程在我们完成所有线程产生之前就会关闭,而只有那些相似的线程会随时存在。然后我在 SortedStringArray 的另一个线程中执行二进制文件。