[英]How does the following regex work?
假設我有一個字符串,我想從一個開頭的雙引號解析為結束雙引號:
asdf"pass\"word"asdf
我很幸運地發現以下PCRE會從開頭雙引號到結束雙引號匹配,同時忽略中間的轉義雙引號(正確解析邏輯單元):
".*?(?:(?!\\").)"
比賽:
"pass\"word"
但是,我不知道為什么這個PCRE正確地匹配開始和結束雙引號。
我知道以下內容:
“=字面雙引號
。*? =任何字符的零或更多的惰性匹配
(?:=打開非捕獲組
(?!\\“)=斷言它不可能匹配文字\\”
。 =單個字符
)=關閉非捕獲組
“=字面雙引號
看起來單個字符和負前瞻是同一邏輯組的一部分。 對我來說,這意味着PCRE會說“只要字符后面沒有\\”,就可以從雙引號到零或更多的字符匹配,然后再匹配一個字符和一個雙引號。“
但是,根據該邏輯,PCRE根本不匹配字符串。
有人可以幫助我繞過這個嗎?
如果將非捕獲組更改為捕獲組,則更容易理解。
懶惰匹配通常一次向前移動一個角色(相對於貪婪匹配它可以然后放棄它必須的東西)。 但是,只要滿足模式之后所需的部分,它就會“前進”,這是通過讓.*?
將所有內容與r
匹配,然后讓負面預測+ .
匹配d
。
更新:您在評論中提問:
它怎么會與
r
匹配呢? 不應該是消極的前瞻阻止它在字符串中傳遞\\"
感謝幫助我理解,順便說一下
不,因為它不是匹配它的負面前瞻性東西。 這就是為什么我建議您將未捕獲的組更改為捕獲的組,以便您可以看到它.*?
匹配\\"
,而不是(?:(?!\\\\").)
.*?
有可能匹配整個字符串,正則表達式引擎使用它來滿足匹配模式其余部分的要求。
更新2:
它實際上與執行此操作相同: ".*?[^\\\\]"
這可能更容易包裹你的頭腦。
一個(略微)更好的模式是使用負面的lookbehind如下: ".*?(?<!\\\\)"
因為它將允許匹配一個空字符串""
(在許多上下文中有效匹配),但是所有引擎/語言都不支持負面的lookbehinds(從你的標簽,pcre支持它,但我認為你不能在bash中真正做到這一點,除了例如grep -P '[pattern]' ..
它基本上運行它通過perl)。
沒有什么可以添加到Crayon Violent的解釋,只有一點消歧和方法來匹配雙引號之間的子串(最終引號被反斜杠內部轉義)。
首先,您似乎在您的問題中使用了首字母縮略詞“PCRE”(Perl Compatible Regular Expression),它是特定正則表達式引擎的名稱(並且通過擴展或有些不精確地指代其語法)來代替單詞“pattern”這是描述一組其他字符串的正則表達式(無論使用何種正則表達式引擎)。
使用Bash:
A='asdf"pass\"word"asdf'
pattern='"(([^"\\]|\\.)*)"'
[[ $A =~ $pattern ]]
echo ${BASH_REMATCH[1]}
您也可以使用此模式: pattern='"(([^"\\\\]+|\\\\.)*)"'
使用PCRE正則表達式引擎,您可以使用第一種模式,但最好以更有效的方式重寫它:
"([^"\\]*+(?:\\.[^"\\])*+)"
請注意,對於這三種模式,不需要任何環視。 他們能夠處理任意數量的連續反斜杠: "abc\\\\\\"def"
(字面反斜杠和轉義引號) , "abcdef\\\\\\\\"
(兩個字面反斜杠,引號未轉義) 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.