经典正则表达式等价于有限自动机。大多数当前的“正则表达式”实现并不严格地说正则表达式,但更强大。有些人开始使用术语“模式”而不是“正则表达式”来更准确。
使用现代“正则表达式”(例如Perl 5中支持的模式)可以描述的形式语言分类是什么?
更新:“Perl 5”我的意思是在Perl 5中实现的模式匹配功能,并被许多其他语言(C#,JavaScript等)采用,而不是Perl特有的任何东西。我不想考虑,例如,在模式中嵌入Perl代码的技巧。
答案 0 :(得分:4)
Perl regexps,就像允许“反向引用”的任何模式语言一样,实际上并不是“常规”。
反向引用是匹配在之前与子模式匹配的相同字符串的机制。例如,/^(a*)\1$/
仅匹配偶数个a
s的字符串,因为在某些a
之后,应该遵循相同数量的字符串。
很容易证明,例如,模式/^((a|b)*)\1$/
匹配来自非常规语言(*)的单词,因此蚂蚁有限自动机更具表现力。正则表达式不能“记住”任意长度的字符串然后再次匹配(长度可能很长,而有限状态机只能模拟有限量的“内存”)。
正式证据将使用pumping lemma。 (顺便说一下,这种语言也不能通过无上下文语法来描述。)
更不用说tricks that allow to use perl code in perl regexps(那里有平衡括号的非常规语言)。
(*)“常规语言”是由有限自动机匹配的单词集。我已经写过an answer了。
答案 1 :(得分:2)
我一直听说perl的正则表达式实现被描述为具有回溯的NFA。维基百科似乎对此有一点看法:
这可能有点过于模糊,但它的信息却不那么简单:
至少有三种不同 算法决定是否以及如何 给定正则表达式匹配a 字符串。
最古老,最快的两个依靠a 导致形式语言理论 允许每个不确定的有限 要转换的状态机(NFA) 进入确定性有限状态 机器(DFA)。 DFA可以 明确构造然后继续运行 结果输入字符串一个符号 一次。构建一个DFA 正则表达式的大小为m 时间和内存成本为O(2m),但它 可以在大小为n的字符串上运行 时间O(n)。另一种方法是 直接模拟NFA, 基本上建立每个DFA状态 需求然后丢弃它 下一步,可能有缓存。这个 保持DFA隐含并避免 指数建设成本,但 运行成本上升到O(nm)。该 显式方法称为DFA 算法和隐式方法 NFA算法。两者都可以看出来 作为不同的执行方式 相同的DFA,它们也经常被称为 没有制作的DFA算法 区别。这些算法是 快,但用它们来召回 分组子表达式,懒惰 量化和类似的功能 很棘手。[12] [13]
第三种算法是匹配 对输入字符串的模式 回溯。这个算法是 通常称为NFA,但这个 术语可能令人困惑。它的 运行时间可以是指数,其中 简单实现展示何时 匹配表达式 (a | aa)* b包含两个交替 和无限的量化和力量 算法考虑一个 数量呈指数增长 子的情况。更复杂 实现通常会识别 并加快或中止常见病例 否则他们会慢慢跑。
虽然回溯实施 只给出一个指数保证 最坏的情况,他们提供了很多 更大的灵活性和表现力 功率。例如,任何实现 允许使用 反向引用,或实现 Perl引入的各种扩展, 必须使用回溯 实施
有些实现尝试提供 两个算法中最好的一个 运行快速DFA匹配,看看是否 string匹配正则表达式 在所有情况下,只有在那种情况下执行 可能更慢的回溯 匹配。
答案 2 :(得分:2)
最近有一个关于这个主题的讨论是Perlmonks:Turing completeness and regular expressions