閱讀239 返回首頁    go 技術社區[雲棲]


《正則表達式經典實例(第2版)》——2.21 把部分的正則匹配添加到替代文本中

本節書摘來自異步社區《正則表達式經典實例(第2版)》一書中的第2章,第2.21節,作者: 【美】Jan Goyvaerts , Steven Levithan著,更多章節內容可以訪問雲棲社區“異步社區”公眾號查看

2.21 把部分的正則匹配添加到替代文本中

問題描述
匹配任意10個數字的連續序列,如1234567890。並把這個序列轉換成(美國)電話號碼的常見格式,如(123) 456-7890,

解決方案
正則表達式

\b(\d{3})(\d{3})(\d{4})\b
正則選項:無
正則流派:.NET、Java、JavaScript、PCRE、Perl、Python、Ruby

替代文本

($1)●$2-$3
替代文本流派:.NET、Java、JavaScript、PHP、Perl
(${1})●${2}-${3}
替代文本流派:.NET、PHP、Perl
(\1)●\2-\3
替代文本流派:PHP、Python、Ruby

討論
使用捕獲分組的替代
實例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時)則把對不存在分組的引用當作是替代文本中的字麵文本。

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

使用命名捕獲的解決方案
正則表達式

\b(?<area>\d{3})(?<exchange>\d{3})(?<number>\d{4})\b
正則選項:無
正則流派:.NET、Java 7、XRegExp、PCRE 7、Perl 5.10、Ruby 1.9
\b(?'area'\d{3})(?'exchange'\d{3})(?'number'\d{4})\b
正則選項:無
正則流派:.NET、PCRE 7、Perl 5.10、Ruby 1.9
\b(?P<area>\d{3})(?P<exchange>\d{3})(?P<number>\d{4})\b
正則選項:無
正則流派:PCRE、Perl 5.10、Python

替代文本

(${area})●${exchange}-${number}
替代文本流派:.NET、Java 7、XRegExp
(\g<area>)●\g<exchange>-\g<number>
替代文本流派:Python
(\k<area>)●\k<exchange>-\k<number>
替代文本流派:Ruby 1.9
(\k'area')●\k'exchange'-\k'number'
替代文本流派:Ruby 1.9
($+{area})●$+{exchange}-$+{number}
替代文本流派:Perl 5.10
($1)●$2-$3
替代文本流派:PHP

支持命名捕獲的流派
如果你在正則表達式中使用了命名捕獲分組,那麼在.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中混合使用命名和編號。要麼所有分組都命名,要麼所有分組都不命名。對於命名分組,應該總是使用命名的反向引用。

最後更新:2017-06-02 19:36:00

  上一篇:go  Docker技術入門與實戰(第2版)1.1 什麼是Docker
  下一篇:go  《正則表達式經典實例(第2版)》——2.20 在替代文本中添加正則匹配