《精通正則表達式》筆記 --- 選擇引號內的文字


這個例子出自《精通正則表達式》,做一下筆記幫助理解和記憶。

第一版

最簡單的case就是考慮包含一對引號,那么寫出來的表達式應該是這樣的:

".*"

但是這個未免太簡單了吧,會有啥問題呢?假如輸入的字符串長這樣結果就會出問題拉。see...

Input String: "Hello" and "World" Regex: ".*" Match: "Hello" and "World"

為什么會全部匹配到呢?這是因為 * 是一個greedy(匹配優先)的量詞,我覺得英文的意思更容易幫助我們理解。這意味着它會首先會'貪婪'得把所有的字符匹配完,匹配到最后一個字符發現沒有字符可以匹配了,於是開始匹配下一個引號,它會首先回朔到最后一個引號前,然后開始匹配引號匹配引號,發現可以匹配,然后就完成了。這就是為啥整個字符串都被匹配了。

第二版

既然是因為greedy的量詞導致的這個問題,那我們將其給成lazy(忽略優先)的量詞 ----- *? 。當一個量詞是忽略優先的話,那在匹配的時候,引擎會選擇忽略這個忽略優先量詞修飾的字符去匹配下一個字符,如果匹配則繼續,如果不匹配則返回來匹配這個忽略優先量詞修飾的字符。

看一下這個例子,將表達式稍作修改,匹配結果就變鳥。

Input String: "Hello" and "World" Regex: ".*?" Match-1: "Hello" Match-2: "World"

好了,似乎這個版本已經圓滿完成我們的任務啦。

第三版

那我們將需求繼續變化一下,在程序的世界里有一種東西叫做轉移字符,比如有個字符串長這樣子\"Hello, World!\"+\"。 直接上最終正則表達式。

Input String: \"Hello, World!\"+\" Regex: "(\\.|[^\\"])*" Match-1: No Match

正則表達式中關鍵的是這個(\\.|[^\\"]),這個括號在正則表達式里是起到一個多選結構的作用,表示匹配括號內任意一個子表達式即匹配。這個括號里面由兩部分,第一部分是\\.,第二部分是[^\\"]

\\.

\\.能夠匹配任何的轉義字符,嚴格來說是匹配任意\以及其后面的字符,即使它們不是真正的轉義字符。

[^\"]

這個輸入字符串最后一個引號是轉移的引號,所以這個正則表達式沒有匹配到任何的結果。這個結果是對的,這個功勞就要歸結到這個[^\\"],它的意思是匹配非\"的任意字符。當引擎匹配到字符串最后發現"還未匹配,於是進行回溯,回溯到▴那個位置\"Hello, World!\"+ ▴ \"。引擎會嘗試去匹配[^\\"],發現匹配失敗,於是失敗!

假如我們將[^\\"]換成[^"],那么在剛才那個位置的時候,[^"]就會匹配\字符,然后\之后的"會被外層的引號匹配,於是它的結果就是被匹配了。這顯然是很奇怪的,當然如果你想要這么匹配也可以。

其他版本

還有一種方式是利用正則表達式里面的固化分組(Atomic grouping)或者占有優先量詞(Possessive)。固化分組:"(?>(\\.|[^"])*),占有優先量詞:"(\\.|[^"])*+"。在固化分組或者占有優先量詞的匹配過程中,在固化分組內或者占有優先量詞修飾的組內,如果一個字符已經被匹配那么之前的狀態將會被舍棄,就防止它進行回溯。

在這個例子中,\"Hello, World!\"+\",當匹配到這個位置的時候(\"Hello, World!\"+\" ▴)發現沒有辦法繼續匹配下去了,引擎會選擇直接匹配失敗,而不是回溯到之前的備用狀態進行新的匹配。

關鍵的概念

例子雖然簡單,但是出現了正則表達式中很多關鍵的概念,預知詳情,請閱讀《精通正則表達式》

  • 匹配優先量詞(Greedy quantifier)
  • 忽略優先量詞(Lazy quantifier)
  • 占有優先量詞(Possessive quantifier)
  • 固化分組(Atomic grouping)
  • 字符組(Character Classes)
  • 多選結構(Alternation)

本文純屬個人讀書筆記,如有錯誤概不負責喲~~~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM