天天看點

《正規表達式經典執行個體(第2版)》——2.21 把部分的正則比對添加到替代文本中

本節書摘來自異步社群《正規表達式經典執行個體(第2版)》一書中的第2章,第2.21節,作者: 【美】jan goyvaerts , steven levithan著,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視

問題描述

比對任意10個數字的連續序列,如1234567890。并把這個序列轉換成(美國)電話号碼的常見格式,如(123) 456-7890,

解決方案

正規表達式

替代文本

讨論

使用捕獲分組的替代

執行個體2.10講解了在正規表達式中如何使用捕獲分組來多次比對相同的文本。在正規表達式中,每個捕獲分組比對到的文本在每次成功比對之後都是可用的。你可以把部分或者所有捕獲分組中的文本按照任意順序甚至多次插入到替代文本中。

一些流派,如python和ruby,在正規表達式和替代文本中對于反向引用使用相同的文法«1»。其他流派使用的則是perl中的文法«$1»,也就是說使用的是美元符号而不是反斜杠。php對于兩種文法都支援。

在perl中,«$1»以及更高編号的分組實際上都是變量,它們的值會在每次正則比對成功之後進行設定。你可以在代碼中的任意地方使用它們,直到下一次正則比對開始。.net、java、javascript和php隻在替代文本文法中支援«$1»。這些程式設計語言還提供了其他在代碼中通路捕獲分組的方式。這會在第3章中詳細解釋。

$10及更多分組

本書中的所有正則流派都支援在單個正規表達式中使用最多99個捕獲分組。在替代文本中,對于«$10»或«10»以及更多的分組則會産生二義性。這些可以被解釋為是第10個捕獲分組,或者是第一個捕獲分組後跟着一個字面上的0。

.net、xregexp、php和perl允許在數字周圍使用花括号來澄清意圖。«${10}» 總是代表第10個捕獲分組,而«${1}0»則總是意味着第一個分組後跟着一個字面上的0。

java和javascript對于«$10»使用了更加聰明的處理辦法。如果在你的正規表達式中存在這個兩位數的捕獲分組的話,那麼兩位數字都會用于引用捕獲分組。如果并不存在這麼多捕獲分組的話,那麼隻有第一個數字用來引用分組,這樣第二個數字就當作了字面字元。是以«$23»隻有在它存在的時候才被認為是第23個捕獲分組。否則,它被當作是第2個捕獲分組後面跟着一個字面上的«3»。

.net、xregexp、php、perl、python和ruby總是把«$10»和«10»視為第10個捕獲分組,而不管它們是否真的存在。如果它不存在的話,就會出現引用不存在的分組的狀态。

對不存在的分組的引用

在這個執行個體的解決方案中的正規表達式擁有3個捕獲分組。如果你在替代文本中輸入了«$4»或«4»,就添加了一個對不存在的捕獲分組的引用。這可能會觸發如下的3種不同的行為。

java、xregexp和python會報錯,并且抛出異常或者傳回錯誤消息。是以不要在這些流派中使用無效的反向引用。(事實上,你不應當在任何流派中使用無效的反向引用。)如果想要添加的是字面上的«$4»或«4»,就需要對美元符号或反斜杠進行轉義。執行個體2.19中對此有詳細的解釋。

php、perl和ruby會替換在替代文本中所有的反向引用,也包括了那些指向不存在的分組的引用。不存在的分組顯然不會捕獲任何文本,是以對它們的引用也就簡單地被替換為空。

最後,.net和javascript(未使用xregexp時)則把對不存在分組的引用當作是替代文本中的字面文本。

如果某個分組在正規表達式中存在,比對中卻沒有捕獲到任何東西,無論是什麼流派,它仍然可以在替換文本中使用,隻不過它們真實的值是空串。

使用命名捕獲的解決方案

支援命名捕獲的流派

如果你在正規表達式中使用了命名捕獲分組,那麼在.net、java 7、xregexp、python和ruby 1.9中允許在替代文本中使用命名反向引用。在替代文本使用的命名反向引用文法與正規表達式中使用的不同。

ruby在替代文本中使用與其在正規表達式中一樣的反向引用文法。對于ruby 1.9中的命名捕獲分組,它的文法是«k»或«k'group'»。你可以選擇尖括号也可以選擇單引号,隻看哪種友善。

perl 5.10及以後版本将命名捕獲分組比對的文本儲存在散列變量(hash)%+中。你可以使用$+{name}獲得名為“name”的分組比對的文本。perl在替代文本中插入變量值,是以在替代文本中可以把«$+{name}»視為命名反向引用。

php(使用pcre)在正規表達式中支援命名捕獲分組,但是在替代文本中則不支援。你可以在替代文本中使用編号的反向引用來引用正規表達式中的命名捕獲分組。pcre會對所有命名和不命名的分組進行編号,順序是從左向右。

.net、java 7、xregexp、python和ruby 1.9同樣允許使用編号來引用命名分組。然而,.net對于命名分組則采用了不同的編号政策,這在執行個體2.11中已經進行了講解。不推薦在.net、java 7、xregexp、python或ruby中混合使用命名和編号。要麼所有分組都命名,要麼所有分組都不命名。對于命名分組,應該總是使用命名的反向引用。