2015-09-13 49 views
4

比方說,我有,我想從一個打開雙引號解析爲一個字符串結束的雙引號:以下正則表達式如何工作?

asdf"pass\"word"asdf 

我很幸運地發現,以下PCRE會從開雙匹配-quote到閉雙引號而在中間忽略轉義雙引號(正確地解析邏輯單元):

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

匹配度:

"pass\"word" 

但是,我不知道爲什麼這個PCRE匹配正確的開始和結束雙引號。

我知道如下:?

「=字面雙引號

* =懶惰的零個或多個任意字符匹配

(?:=非捕獲組的開口

(?!\ 「)=斷言它不可能匹配文字\」

。=單個字符

)=非捕獲組的閉合

「=字面雙引號

似乎單個字符和負先行相距相同的邏輯羣組的。對我而言,這意味着PCRE在字符後面說「只要沒有任何字符匹配從雙引號到零或多個字符」,然後再匹配一個字符和一個雙引號。「

然而,根據該邏輯的PCRE不會串都匹配。

有人能幫助我總結我解決此頭?

回答

2

它很容易理解,如果你change the non-capture group to be a capture group

懶惰匹配通常會一次向前移動一個角色(相對於貪婪地匹配一切,然後放棄)它必須)。但是,「前進」,只要滿足後的模式,這是通過讓.*?比賽一切都交給r,然後讓負先行+ .比賽d完成所需的零件。

更新:您在留言問:

怎麼來的相匹配的r呢?不應該看到負向 阻止它在字符串中通過\"?感謝 對助人爲樂我明白了,順便

沒有,因爲它不是被匹配它的負先行的東西。這就是爲什麼我建議你改變非捕獲組爲拍攝組,這樣你可以看到它是.*?相匹配的\",不(?:(?!\\").)

.*?有整個字符串相匹配的潛力,正則表達式引擎使用它來滿足匹配模式其餘部分的要求。

更新2:

它是有效的一樣這樣做:".*?[^\\]"這可能是一個更容易繞到你的頭。

(稍微)更好的模式是使用如下這樣的反向倒序:".*?(?<!\\)",因爲它會允許匹配空字符串""(在許多上下文中有效匹配),但不支持反向lookbehinds所有的引擎/語言(來自你的標籤,pcre支持它,但我不認爲你真的可以在bash中做到這一點,除非例如grep -P '[pattern]' ..基本上通過perl運行它)。

+0

它如何與「r」匹配?不應該負向前視,以防止它通過字符串中的'\「'感謝幫助我明白,順便說一句 – Nolan

+0

@Nolan看到我的更新 –

+0

'bash'不使用Perl風格的正則表達式,只有POSIX -defined [擴展正則表達式](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html#tag_09_04)。 – chepner

0

沒有什麼可以添加到蠟筆暴力的解釋,只有一點消歧和方法來匹配包含在雙引號(最終引號內部反斜槓逃脫)之間的子字符串。

首先,您似乎在您的問題中使用的是縮寫「PCRE」(Perl Compatible Regular Expression),它是特定正則表達式引擎的名稱(通過擴展或稍微不精確地指代其語法)來代替字「模式」,即描述一組其他正則表達式的字符「模式」(無論使用哪種正則表達式引擎)。

使用bash:

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

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

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

有了PCRE正則表達式引擎,可以使用第一圖案,但最好還是把它改寫以更有效的方式:

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

請注意,這三種模式不需要任何查找。它們能夠處理任意數量的連續反斜槓:"abc\\\"def"(文字反斜槓和轉義引用)"abcdef\\\\"(兩個字面反斜槓,引號不會轉義)