|
|
1
23
正如其他答案所声称的,lookarounds不会为正则表达式增加任何额外的功能。 我想我们可以用以下方式来展示: One Pebble 2-NFA (见本文引言部分)。 1-Pebble2NFA不处理嵌套的lookaheads,但是,我们可以使用多Pebble2NFA的变体(参见下面的部分)。 介绍 2-NFA是一种非确定性的有限自动机,能够在输入端左右移动。 一个卵石机器是指机器可以将一个卵石放在输入带上(即用卵石标记一个特定的输入符号),并根据当前输入位置是否有卵石进行可能不同的转换。 众所周知,一个圆石2-NFA有相同的权力,作为一个普通的DFA。 非嵌套lookaheads 基本思路如下: 2NFA允许我们通过在输入磁带中向前或向后移动来回溯(或“前轨”)。因此,对于lookahead,我们可以对lookahead正则表达式进行匹配,然后在匹配lookahead表达式时回溯所消耗的内容。为了准确知道何时停止回溯,我们使用了鹅卵石!我们在进入德国足协(DFA)进行先行检查之前,先放下鹅卵石,以标记回溯需要停止的地方。 因此,在通过Pebble 2NFA运行字符串的末尾,我们知道是否匹配lookahead表达式,而左边的输入(即剩余的要消费的内容)正是匹配剩余内容所需的内容。 那么,对于形式u(?= V)W 我们有u,v和w的dfas。 从dfa的接受状态(是的,我们可以假设只有一个)开始,我们对v的起始状态进行e-转换,用圆石标记输入。 从V的接受状态,我们转换到一个保持输入向左移动的状态,直到它找到一个圆石,然后转换到W的开始状态。 从V的拒绝状态,我们E-转换到一个一直向左移动直到它找到鹅卵石的状态,并转换到U的接受状态(即我们离开的位置)。 用于常规NFA的证据,用于显示R1 R2或R*等,对这一块卵石2NFA进行结转。见 http://www.coli.uni-saarland.de/projects/milca/courses/coal/html/node41.html#regularlanguages.sec.regexptofsa 有关如何将组件机器组合在一起以便为r*表达式等提供更大的机器的详细信息。 上述R*ETC工作证明的原因是,当我们输入组件nfas进行重复时,回溯确保输入指针始终位于正确的位置。另外,如果一个圆石正在使用中,那么它将由一个lookahead组件机器进行处理。由于没有从lookahead机器到lookahead机器的转换,就不需要完全回溯和返回Pebble,所以只需要一个Pebble机器。 例如考虑([^a]a(?=…B)* 以及字符串abbb。 我们有一个abbb,它通过peb2nfa获得了a(?=…b),在其末尾,我们处于状态:(b b b,matched)(即在输入b b b中剩余,它匹配“a”,后跟“…b”)。现在,由于*,我们回到开头(请参见上面链接中的构造),并为[^a]输入dfa。匹配b,返回开头,再次输入[^a]两次,然后接受。 处理嵌套的lookaheads 要处理嵌套的lookaheads,我们可以使用此处定义的受限制版本的k-pebble 2nfa: Complexity Results for Two-Way and Multi-Pebble Automata and their Logics (见定义4.1和定理4.2)。 一般来说,2个卵石自动机可以接受非正则集,但在以下限制条件下,k-卵石自动机可以证明是正则的(本文中的定理4.2)。 如果鹅卵石是P_1,P_2,…,P_k
因此,如果v是深度k的嵌套先行表达式,那么(?=v)是深度k+1的嵌套先行表达式。当我们进入一个先行机器时,我们知道到目前为止必须放置多少个鹅卵石,因此可以精确地确定要放置哪个鹅卵石,当我们退出机器时,我们知道要提升哪个鹅卵石。在深度t处的所有机器都是通过放置Pebble T进入的,而通过移除Pebble T退出的(即我们返回到深度t-1机器的处理)。整个机器的任何运行都像是树的递归DFS调用,并且可以满足多Pebble机器的上述两个限制。 现在,当您组合表达式时,对于r r1,因为您concat,r1的圆石编号必须增加r的深度。对于r*和r r1,圆石编号保持不变。 因此,任何具有lookaheads的表达式都可以转换为等效的多卵石机器,在卵石放置方面有上述限制,因此是规则的。 结论 这基本上解决了Francis最初的证明中的缺点:能够防止lookahead表达式使用将来匹配所需的任何东西。 因为lookbehinds只是有限字符串(不是真正的regex),所以我们可以先处理它们,然后再处理lookaheads。 抱歉,写得不完整,但完整的证据需要画很多数字。 这对我来说是对的,但我很高兴知道有任何错误(我似乎喜欢这样的错误)。 |
|
2
25
对于您所问的问题的答案是否定的,即是否可以通过环顾来增强正则表达式来识别比常规语言更大的语言类。 证明相对简单,但是将包含查找的正则表达式转换为不包含查找的正则表达式的算法是混乱的。 首先:请注意,您总是可以否定正则表达式(在有限字母表中)。给定一个识别表达式生成的语言的有限状态自动机,您可以简单地将所有接受状态交换为不接受状态,得到一个完全识别该语言的否定的FSA,对于该语言,有一系列等价的正则表达式。 第二:因为正则语言(以及正则表达式)在否定下是闭的,所以它们在交集下也是闭的,因为根据德摩根定律,交集b=neg(neg(a)union neg(b))。换句话说,对于给定的两个正则表达式,您可以找到另一个匹配这两个表达式的正则表达式。 这允许您模拟lookaround表达式。例如U?=v)w只匹配将匹配uv和uw的表达式。 对于负向前看,需要等价于集合理论a \b的正则表达式,它只是一个相交(neg b)或等价的neg(neg(a)union b)。因此,对于任何正则表达式r和s,您都可以找到一个正则表达式r-s,它与那些与r不匹配的表达式相匹配。在负先行条件下:u(?!v)w只匹配那些与uw-uv匹配的表达式。 环顾是有用的有两个原因。
首先,因为对正则表达式的否定会导致更不整洁的东西。例如
其次,正则表达式做的不仅仅是匹配表达式,它们还使用字符串中的字符——或者至少这是我们喜欢的思考方式。例如,在Python中,我关心.start()和.end(),因此当然:
第三,我认为这是一个非常重要的原因,正则表达式的否定不能很好地提升到连接上。neg(a)neg(b)与neg(a b)不同,这意味着你不能将lookaround从你找到它的上下文中转换出来——你必须处理整个字符串。我想这会使人们不喜欢和正则表达式一起工作,并破坏人们对正则表达式的直觉。 我希望我已经回答了你的理论问题(深夜,如果我不清楚,请原谅我)。我同意一位评论员的观点,他说这确实有实际的应用。当我试图抓取一些非常复杂的网页时,遇到了同样的问题。 编辑 我为不清楚而道歉:我不相信你能用结构归纳法证明正则表达式+观察的规律性,我的u(?!v)w example就是一个简单的例子。结构归纳法不起作用的原因是,环视的行为方式是非组合的——我在上面试图说明的关于否定的观点。我怀疑任何直接的正式证据都会有很多混乱的细节。我试着想出一个简单的方法来展示它,但却无法想出一个我的头。
用乔希的第一个例子来说明
单独状态A的正则表达式如下所示:
换言之,任何通过消除环顾而得到的正则表达式通常都要长得多,而且要混乱得多。 回应乔希的评论——是的,我认为最直接的证明等效性的方法是通过金融服务管理局。造成这种混乱的是,构建FSA的通常方法是通过一个非确定性的机器——它更容易将u v表示为简单地由u和v的机器构造而成,并向其中两个机器进行epsilon转换。当然,这相当于一个确定性机器,但处于状态指数爆炸的风险中。相反,通过确定性机器进行否定要容易得多。 一般的证明包括取两台机器的笛卡尔积,并选择那些你希望在每一个你想要插入环视图的点上保留的状态。上面的例子在某种程度上说明了我的意思。 我为没有提供建筑而道歉。 进一步编辑: 我找到了一个 blog post 它描述了一种从带有查找功能的正则表达式中生成dfa的算法。它很简洁,因为作者以明显的方式扩展了带有“标记epsilon转换”的NFA-E的概念,然后解释了如何将这种自动机转换为DFA。 我以为这样做是一种方法,但我很高兴有人写了。我想不出这么整洁的东西来。 |
|
|
3
9
我同意其他关于lookaround是正则的文章(也就是说它不向正则表达式添加任何基本功能),但是我有一个论点,它比我看到的其他文章更简单。
我将通过提供一个DFA结构来证明环顾是正常的。只有当一种语言有一个可识别它的dfa时,它才是常规语言。请注意,Perl实际上并没有在内部使用dfas(有关详细信息,请参阅本文): http://swtch.com/~rsc/regexp/regexp1.html ),但我们构建了一个dfa用于证明目的。
为正则表达式构造DFA的传统方法是首先使用汤普森算法构建NFA。给定两个正则表达式片段
|
|
|
4
2
我觉得这里有两个不同的问题:
从实际意义上讲,第一个问题的答案是肯定的。lookaround将提供一个regex引擎, 从根本上说,使用这个功能比不使用的功能更强大。这是因为 它为匹配过程提供了一组更丰富的“锚”。 lookaround允许您将整个regex定义为可能的定位点(零宽度断言)。你可以 对这个功能的功能有一个很好的概述 here . 虽然功能强大,但环顾四周并不能将regex引擎提升到理论之外。 类型3语法对其设置的限制。例如,你永远无法 可靠地 基于 Context Free - Type 2 Grammar 使用Regex引擎 装备有了望台。Regex引擎的功率仅限于 Finite State Automation 这从根本上限制了他们可以解析的任何语言的表达能力,使其达到3类语法的水平。不管 在regex引擎中添加了多少“技巧”,这些语言是通过 Context Free Grammar 将始终超出其能力范围。分析上下文无关的-2型语法需要下推自动化来“记住”它在哪里 递归语言结构。任何需要对语法规则进行递归评估的内容都不能使用 正则表达式引擎。 总而言之:lookaround为regex引擎提供了一些实际的好处,但不会在 理论水平。 编辑 在类型3(常规)和类型2(上下文无关)之间是否存在复杂的语法? 我相信答案是否定的,原因是没有理论上的限制 放在NFA/DFA的大小上,用于描述常规语言。它可能变得任意大 因此无法使用(或指定)。在这里,诸如“环顾四周”之类的闪避是有用的。他们 提供一个简短的机制来说明什么会导致非常大/复杂的NFA/DFA。 规格。它们不会增加 常规语言,它们只是使指定它们更加实用。一旦你明白了这一点,它就变成了 很明显,有很多“特性”可以添加到regex引擎中,使它们更强大。 从实际意义上说是有用的——但没有什么能使他们超越 常规语言的限制。 规则语言和上下文无关语言的基本区别在于 不包含递归元素。为了评估递归语言,需要 下推式自动化 “记住”你在递归中的位置。NFA/DFA不堆叠状态信息,因此无法 处理递归。因此,对于非递归语言定义,将有一些nfa/dfa(但是 不一定是一个实际的regex表达式)来描述它。 |
|
|
DotFX · RegEx捕获关键字前但括号后的所有内容 1 年前 |
|
|
Andrus · 如何在sql中查找第二个匹配项 1 年前 |
|
|
iato · 确保正则表达式不从命名材料中的数字中提取 1 年前 |
|
|
vr8ce · 非成对标记中特定字符的正则表达式 1 年前 |
|
|
MARTIN · 交换第一个和最后一个单词,反转所有中间的字符 1 年前 |
|
|
Carsten · 使用最近的搜索模式更改文本块 1 年前 |