让我们说我有一个字符串,我想用一个开头的双引号解析为结束双引号:
asdf"pass\"word"asdf
我很幸运地发现以下PCRE会从开头双引号到结束双引号匹配,同时忽略中间的转义双引号(正确解析逻辑单元):
".*?(?:(?!\\").)"
匹配度:
"pass\"word"
但是,我不知道为什么这个PCRE正确匹配开头和结束双引号。
我知道以下内容:
" = literal double-quote
。*? =任何字符零或更多的延迟匹配
(?:=打开非捕获组
(?!\")=断言它不可能与文字匹配\"
。 =单个字符
)=关闭非捕获组
" = literal double-quote
似乎单个字符和负前瞻是同一逻辑组的一部分。对我来说,这意味着只要没有\" PCRE就会说"从双引号匹配到任何字符的零或更多。在角色之后,然后匹配另一个角色和一个双引号。"
但是,根据该逻辑,PCRE根本不匹配字符串。
有人可以帮助我解决这个问题吗?
答案 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\\\\"
(两个字面反斜杠,引用是没有逃脱)。