以下正则表达式如何工作?

时间:2015-09-13 01:01:47

标签: regex bash pcre

让我们说我有一个字符串,我想用一个开头的双引号解析为结束双引号:

asdf"pass\"word"asdf

我很幸运地发现以下PCRE会从开头双引号到结束双引号匹配,同时忽略中间的转义双引号(正确解析逻辑单元):

".*?(?:(?!\\").)"

匹配度:

"pass\"word"

但是,我不知道为什么这个PCRE正确匹配开头和结束双引号。

我知道以下内容:

" = literal double-quote

。*? =任何字符零或更多的延迟匹配

(?:=打开非捕获组

(?!\")=断言它不可能与文字匹配\"

。 =单个字符

)=关闭非捕获组

" = literal double-quote

似乎单个字符和负前瞻是同一逻辑组的一部分。对我来说,这意味着只要没有\" PCRE就会说"从双引号匹配到任何字符的零或更多。在角色之后,然后匹配另一个角色和一个双引号。"

但是,根据该逻辑,PCRE根本不匹配字符串。

有人可以帮助我解决这个问题吗?

2 个答案:

答案 0 :(得分:2)

如果您change the non-capture group to be a capture group,则更容易理解。

懒惰匹配通常一次向前移动一个角色(相对于贪婪匹配它可以然后放弃它必须的东西)。但它已经向前发展了#34;至于满足模式之后所需的部分模式,这是通过让.*?将所有内容与r匹配来实现的,然后让负前瞻+ .与{{1}相匹配}}。

更新:您在评论中提问:

  

为什么它与d完全匹配?不应该是消极的   lookahead阻止它传递给字符串中的r?谢谢   顺便提一下,帮助我理解

不,因为它不是匹配它的负面前瞻性东西。这就是为什么我建议您将未捕获的组更改为捕获的组,以便您可以看到\".*?匹配,而不是\"

(?:(?!\\").)有可能匹配整个字符串,正则表达式引擎使用它来满足匹配模式其余部分的要求。

更新2:

它实际上与执行此操作相同:.*?这可能更容易包裹你的头脑。

一个(略微)更好的模式是使用负面的lookbehind,如:".*?[^\\]",因为它将允许匹配一个空字符串".*?(?<!\\)"(在许多上下文中有效匹配),但所有引擎/语言都不支持负面的lookbehinds(从你的标签,pcre支持它,但我不认为你可以在bash中真正做到这一点,除了""基本上通过perl运行它)。

答案 1 :(得分:0)

没有什么可以添加到蜡笔暴力解释,只有一点消歧和方法来匹配双引号之间的子串(最终引用内部反斜杠转义)。

首先,您似乎在您的问题中使用了首字母缩略词“PCRE”(Perl Compatible Regular Expression),它是特定正则表达式引擎的名称(并通过扩展或有些不精确地指其语法)代替单词“pattern”,它是描述一组其他字符串的正则表达式(无论使用何种正则表达式引擎)。

使用Bash:

A='asdf"pass\"word"asdf'
pattern='"(([^"\\]|\\.)*)"'

[[ $A =~ $pattern ]]
echo ${BASH_REMATCH[1]}

您也可以使用此模式:pattern='"(([^"\\]+|\\.)*)"'

使用PCRE正则表达式引擎,您可以使用第一种模式,但最好以更有效的方式重写它:

"([^"\\]*+(?:\\.[^"\\])*+)"

请注意,对于这三种模式,不需要任何环视。他们能够处理任意数量的连续反斜杠:"abc\\\"def" (字面反斜杠和转义引用)"abcdef\\\\" (两个字面反斜杠,引用是没有逃脱)