我正在尝试使用扩展正则表达式匹配AB
和BA
之间的内容,例如使用awk
。
考虑两个示例字符串AB12BABA
和AB123BABA
,我尝试了以下正则表达式
AB([^B]|([^B][^A]|B[^A]|[^B]A))*BA
但它匹配两个例子的整个字符串(贪婪)。
任何人都可以解释正则表达式引擎如何适用于这种情况,以及我应该如何更改我的正则表达式以使其正常工作。
答案 0 :(得分:3)
BRE和ERE引擎将与最左边的最长规则匹配,这与Perl和其他基于NFA的正则表达式引擎与正则表达式的匹配方式不同。
Boost库中的documentation在技术方面更加详细,所以我在这里引用它:
最左边的最长规则
通常,在特定位置匹配正则表达式的方法不止一种,对于POSIX基本和扩展正则表达式,“最佳”匹配确定如下:
- 找到最左边的匹配项,如果此位置只有一个匹配项,则返回它。
- 找出最长的可能比赛以及任何比赛。如果只有一个这样的可能匹配,则返回它。
- 如果没有标记的子表达式,则所有剩余的替代方案都难以区分;返回第一个找到的。
- 找到与最左边位置的第一个子表达式匹配的匹配项以及任何关系。如果只有这样的匹配可以返回它。
- 找到第一个子表达式匹配最长的匹配项以及任何联系项。如果只有一个这样的匹配则返回。
- 对每个其他标记的子表达式重复步骤4和5。
- 如果仍有多个可能的匹配,则它们无法区分;返回找到的第一个。
醇>
文本中提到的标记子表达式指的是()
捕获组。请注意,它们仅支持捕获和反向引用。
因此,为了进行延迟匹配,您需要构造一个正则表达式,使其与重复的部分匹配,而避免匹配尾部直到最后。由于ERE和BRE等同于理论正则表达式,只要你能构造一个DFA,就会存在一个等效的正则表达式(只是在某些情况下构造它并不是一件容易的事)。
根据您的要求,此正则表达式应该起作用:
AB([^B]|B+[^AB])*B*BA
部分([^B]|B+[^AB])*B*
匹配任何不包含字符串“BA”的字符串。
这是匹配不包含字符串“BA”的字符串的DFA。
这里的符号不是标准的,所以我会解释一下:
*
表示字母表中的任何字符。 [^B]
表示除B之外的字母表中的任何字符。在DFA中,q0和q1是最终状态,q0是初始状态。请注意,q2是陷阱状态,因为它是非最终状态,并且没有从该状态转换出来。
使用步骤here,或只使用JFLAP派生正则表达式。 (在JFLAP中,您应该使用某些字符,例如C
来表示[^AB]
)。
由于q2是陷阱状态,我们可以将其从公式中排除:
R0 = [^B]R0 + BR1 + λ
R1 = [^AB]R0 + BR1 + λ
将Arden定理应用于R1:
R1 = B*([^AB]R0 + λ)
将R1替换为R0:
R0 = [^B]R0 + BB*([^AB]R0 + λ) + λ
在BB*
上分发([^AB]R0 + λ)
:
R0 = [^B]R0 + BB*[^AB]R0 + BB*λ + λ
组合在一起:
R0 = ([^B] + BB*[^AB])R0 + (BB* + λ)
将Arden定理应用于R0:
R0 = ([^B] + BB*[^AB])*(BB* + λ)
(BB*
OR λ
(空字符串))相当于B*
:
R0 = ([^B] + BB*[^AB])*B*
让我们将其重写为awk
的语法:([^B]|B+[^AB])*B*
,如上所示。
答案 1 :(得分:0)
使用环顾四周和非贪婪的量词:
(?<=AB).*?(?=BA)
如果您想匹配分隔符,只需:
AB.*?BA