讀書筆記《Mastering Regular Expressions》(四)

來源:互聯網
上載者:User

一、問題

將一個數值字串,從右向左,每三位用逗號分開,比如,將“123456789”替換為“123,456,789”。

二、分析

替換演算法的本質是將字串從右向左,每3個字元為一組進行分組,然後在組與組之間插入逗號。

三、文法

Regex引入了“預測”和“回顧”這兩個概念,它們不是匹配字串,而是匹配一個“位置”,其中預測是正向(自左向右)查看,回顧是反向(自右向左)查看。

(下表中圓括弧及其括住的內容,只匹配位置,不匹配文本)
Regex 名稱 說明 樣本
(?=...) 預測 斷言子運算式在此位置的右側 abcd(?=/d) 匹配右側緊跟數位abcd
(?!...) 否定預測 斷言子運算式不在此位置的右側 abcd(?!/d) 匹配右側緊跟的不是數位abcd
(?<=...) 回顧 斷言子運算式在此位置的左側 (?<=/d)abcd 匹配左側是數位abcd
(?<!...) 否定回顧 斷言子運算式不在此位置的左側 (?<!/d)abcd 匹配左側不是數位abcd

預測和回顧只是匹配一個位置,其中的子運算式並不被匹配。比如有字元“ABCDEFG”,則Regex

(?=EFG)(?<=ABCD)或(?<=ABCD)(?=EFG)

就匹配D與E之間的那個位置,而不是匹配EFG,也不匹配ABCD,或其他任何一個字串。 注意,由於只是斷言一個位置,所以上述預測和回顧的先後次序並不重要,二者同樣都是匹配D與E之間的那個位置。前者的含義是“匹配一個位置,它的右邊是 EFG,左邊是ABCD”,後者的含義是“匹配一個位置,它的左邊是ABCD,右邊是EFG”,兩者都是同一個意思。下面的Perl在ABCD和EFG之 間插入一個逗號:

$foo = "ABCDEFG";
$foo =~ s/(?<=ABCD)(?=EFG)/,/;
print $foo;

假定要把某段文本中所有的Jeffs都替換為Jeff's(匹配到單詞邊界),那麼,就會有如下幾種方案:

方案 說明
s//bJeffs/b/Jeff's/g 這是最直觀的方法,直接把匹配到的Jeffs替換為Jeff's
s//b(Jeff)(s)/b/$1'$2/g 分組構造,在兩個組之間插入單引號
s//bJeff(?=s/b)/Jeff'/g 預測,僅匹配“後面緊跟s並在單詞邊界的Jeff”的右側那個位置
(其它的如Jeffrey中的Jeff不被匹配)
s/(?<=/bJeff)(?=s/b)/'/g 同時使用預測和回顧,在匹配位置處插入單引號
s/(?=s/b)(?<=/bJeff)/'/g 與上面的行為完全相同,由於預測和回顧只是匹配位置而不是匹配字串,所以先後次序不重要了。
四、解決問題

利用預測和回顧,就可以解決“在數值中插入逗號”的問題了。插入演算法是:從右向左把數字,每3個分為一組,在組與組之間插入逗號。也就是說,只要匹配到這些位置,就可以在這些位置上插入逗號。

$foo = "123456789";
$foo =~ s/(?=/d/d/d)/,/g;
print $foo;

上面的結果是“,1,2,3,4,5,6,789”,顯然不是想要的。

Regex 結果 說明
s/(?=/d/d/d)/,/g
s/(?=(/d/d/d)+)/,/g
,1,2,3,4,5,6,789 1左邊的位置被匹配,因為該位置右邊有3個數字(123)
同理,1右邊的位置也被匹配,該位置右邊有3個數字(234)……
而7的右邊位置不再被匹配,因為該位置右邊不再有3個數字
s/(?=/d/d/d$)/,/g 123456,789 只有7左邊的位置被匹配,因為該點符合以下兩個條件:
其右邊是3個數字,
且這3個數字在行尾(其右側什麼也沒有了)。
s/(?=(/d/d/d)+$)/,/g ,123,456,789 1左邊的位置符合條件“其右側有N組(每組3個數字),且最後一組在行尾”;
2左邊的位置不符合該條件,因為其後面是234、567和89,最後的89無法構成一組;
其它同理……
s/(?=(/d/d/d)+$)(?<=/d)/,/g 123,456,789 1左邊的位置不再被匹配,因為(?<=/d)的存在,它指示該位置的左側必須是數字,
而1左邊的位置顯然不符合。

這個Regex替換單個的數字串沒問題,但如果想要將“The population of 281421906 is growing”中的281421906替換成281,421,906就無能為力了,原因是$限定了最後一組(3個)數字必須在行尾,因此需要把條件修正為“最後一組數位右邊不是數字”,這就要用到“否定預測”:

s/(?=(/d/d/d)+(?!/d))(?<=/d)/,/g

(微軟VBScript.DLL提供的COM對象IRegExp2,文檔裡說支援“回顧”文法,但實際運用卻會拋出一個異常,不知何故)

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.