给定两个字符串作为参数,一个是正则表达式字符串,另一个是文本。如何在不使用任何内部库或模块的情况下编写标识给定正则表达式是否与文本匹配的函数?
答案 0 :(得分:1)
希望这个问题仅用于教育目的,因为编写执行正则表达式匹配的代码是一项非常艰巨的任务。
基本上有两种方法:
1)正则表达式可以转换为确定性有限自动机(DFA),可以很容易地用于查找任何字符串中的匹配项。见(https://en.wikipedia.org/wiki/Deterministic_finite_automaton)。
该过程包括首先使用Thompson的构造(https://en.wikipedia.org/wiki/Nondeterministic_finite_automaton)转换为非确定性有限自动机(NFA - https://en.wikipedia.org/wiki/Thompson%27s_construction),然后使用子集构造将其转换为DFA({{3} }),然后使用Hopcroft的算法或类似的(https://en.wikipedia.org/wiki/Powerset_construction)
最小化DFA这种方法的优点是无论原始正则表达多么复杂,都可以生成非常快的匹配器。它有一些缺点,包括无法处理反向引用。
编译器使用此技术来标记程序以进行解析。我有一个用Java实现的开源库:https://en.wikipedia.org/wiki/DFA_minimization
2)另一种方法,通常称为“回溯”方法,将正则表达式转换为可能性树。当你在这棵树上匹配一个字符串时,它首先尝试第一种可能性,然后如果失败则返回并尝试对照字符串的相同部分的下一种可能性。这更容易实现,但速度不是特别快。
在某些情况下,匹配字符串可能需要很长时间。例如,请参阅http://mtimmerm.github.io/dfalex/
尽管如此,这是在大多数语言提供的库中完成的,包括Java,C#,Perl等。与标准实现最接近的是PCRE,或“与Perl兼容的正则表达式”:{{3} }
3)......还有很多不太常见的方法。有些软件包类似于(1),但是动态执行子集构造并且只构建所需的状态。有些人直接执行NFA(http://www.regular-expressions.info/catastrophic.html)。有些像(2)但是一次尝试多个分支。这两种方法都避免了灾难性的情况。一些解析技术(如GLR解析(http://www.pcre.org/))也可用于实现总是以合理方式执行的非常快速的正则表达式引擎。