簡體   English   中英

以下正則表達式如何工作?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM