正則表達(dá)式高級(jí)用法

引子

上一章分享了正式表達(dá)式的入門(mén)知識(shí),以及單字符、多字符常用的匹配方法,對(duì)于工作維護(hù)過(guò)程中已經(jīng)夠用,但是有時(shí)候只使用基礎(chǔ)知識(shí)來(lái)實(shí)現(xiàn)就會(huì)比較麻煩,如果使用高級(jí)用法就會(huì)比較方便很多。
例如:匹配一個(gè)HTML文件中兩個(gè)<B>標(biāo)簽中的文件。
文本內(nèi)容:

This offer is not available to customers living in <B>AK</B> and <B>HI</B>

從上一章內(nèi)容的知識(shí)可以想到的表達(dá)式可能如下:

<[Bb]>.*</[Bb]>

但是這個(gè)表達(dá)式配置的結(jié)果是AK</B> and <B>HI,而不是我們想要的AKHI。

懶惰型匹配

引子中的例子中的匹配方式是屬于貪婪行為,就是盡可能多的匹配內(nèi)容,像例子中第一個(gè)<B>和最后一個(gè)</B>中間都被匹配到了,而不管匹配內(nèi)容中是否存在</B>。
上一章中講到的*和+、{m,}都是所謂的“貪婪型”的。在這一節(jié)中講一下與“貪婪型”相反的“懶惰型”,就是匹配盡可能少的內(nèi)容。

實(shí)現(xiàn)很簡(jiǎn)單,就是在原有“貪婪型”元字符后面加上一個(gè)? 號(hào),如下表格

貪婪型元字符 懶惰型元字符
* *?
+ +?
{m,} {m,}?

位置匹配

在現(xiàn)實(shí)的系統(tǒng)中一般表達(dá)位置的地方就是一個(gè)單詞的開(kāi)頭以及結(jié)尾或者一個(gè)字符串的開(kāi)頭或者結(jié)尾。
注意這個(gè)邊界只是一個(gè)位置,例如單詞邊界匹配的是\w\W之間的一個(gè)位置

元字符 說(shuō)明 注意
\b 單詞邊界,單詞的開(kāi)頭或者單詞的結(jié)尾 回退鍵的元字符是[\b]
\B 表示非單詞邊界
^ 字符串的開(kāi)頭位置 放在[]中表示取非操作
$ 字符串結(jié)尾位置

擴(kuò)展:

  • 像egrep中也支持使用\<匹配單詞開(kāi)頭位置,使用\>匹配單詞結(jié)尾位置,但是支持這種元字符的編輯器比較少。
  • (?m)是一個(gè)分行匹配模式的記號(hào),放在一個(gè)表達(dá)式的最前面,會(huì)改變字符串位置匹配的行為。^不僅匹配正常的字符串開(kāi)頭還匹配行分隔符(換行符)后面的開(kāi)始位置;同樣$不僅匹配正常的字符串結(jié)尾還匹配行分隔符(換行符)后面的結(jié)束位置;此用法只有部分正則表達(dá)式會(huì)支持
選項(xiàng) 描述 支持平臺(tái)
(?d) Unix中的行 java
(?i) 不區(qū)分大小寫(xiě) PCRE Perl java
(?J) 允許重復(fù)的名字 PCRE*
(?m) 多行 PCRE Perl java
(?s) 單行 PCRE Perl java
(?u) Unicode java
(?U) 默認(rèn)最短匹配,與懶惰型匹配類似 PCRE
(?x) 忽略空格和注釋 PCRE Perl Java
(?-...) 復(fù)原或關(guān)閉選項(xiàng) PCRE

捕獲分組與后向引用

前面的元字符都是對(duì)緊挨著前面的一個(gè)字符有效,例如表達(dá)式the{3}匹配theee字符串,假如我們想匹配連續(xù)三個(gè)the字符串怎么辦呢,這就涉及到子表達(dá)式的概念。

子表達(dá)式

把一個(gè)表達(dá)式匹配的內(nèi)容做為一個(gè)單獨(dú)的元素嵌入到另外一個(gè)表達(dá)式中,那這個(gè)做為獨(dú)立元素的表達(dá)式就是子表達(dá)式,需要使用()括起來(lái)。這個(gè)跟數(shù)學(xué)的表達(dá)式概念很類似。
并且子表達(dá)與數(shù)學(xué)表達(dá)式還有一個(gè)類似的地方就是,正則表達(dá)式的子表達(dá)式也可以嵌套使用

本節(jié)開(kāi)頭說(shuō)的那個(gè)問(wèn)題就可以使用子表達(dá)式來(lái)實(shí)現(xiàn),(the){3}就會(huì)匹配thethethe這個(gè)字符串。

假如我們?cè)偌觽€(gè)條件:我們想匹配連續(xù)三個(gè)the或者連續(xù)三個(gè)you,怎么實(shí)現(xiàn)?這就是正則表達(dá)式的選擇操作符,也叫或操作符了

元字符 說(shuō)明
| 或操作符,兩邊的表達(dá)式都是一個(gè)獨(dú)立的元素,一般放在()中使用

上面的問(wèn)題就可以使用正則表達(dá)式(the|you){3}來(lái)表示

捕獲分組與后向引用

當(dāng)一個(gè)模式的全部或者部分內(nèi)容由一對(duì)括號(hào)括起來(lái)時(shí),就對(duì)表達(dá)式進(jìn)行了分組(其實(shí)就是放在()中的子表達(dá)式),并且把分組匹配到內(nèi)容捕獲并且臨時(shí)存放在內(nèi)存中。這就是捕獲分組,可以在后面表達(dá)式中使用就叫后向引用,或者叫回溯引用。
默認(rèn)情況下,分組是從左到右依次排序從1編號(hào),第一個(gè)分組就是1,第二個(gè)分組就是2等等。

最開(kāi)始的時(shí)候支持的編號(hào)范圍是1到9,現(xiàn)在應(yīng)該已經(jīng)沒(méi)有這種限制了。

后向引用很簡(jiǎn)單就是一個(gè)\或者$后面跟相應(yīng)編號(hào)即可。例如\1或者$1就表示引用第一個(gè)捕獲分組。

命名分組

前面講捕獲分組都是通過(guò)位置編號(hào)來(lái)訪問(wèn),在perl和python、.NET等語(yǔ)言中還支持對(duì)捕獲分組命名。這樣就比較容易理解

命名語(yǔ)法 描述
(?<name>分組) 命名分組
(?P<name>分組) python中的命名分組
\k<name> Perl中引用命名分組
\k'name' Perl中引用命名分組
\g{name} Perl中引用命名分組
\k{name} .NET中引用命名分組
(?P=name) Python中引用命名分組

非捕獲分組

顧名思義,與捕獲分組相反,就是不會(huì)將分組匹配的內(nèi)容放在內(nèi)存中。主要是為了提高性能。
使用方法:在分組的開(kāi)頭加上?:,例如(?:the)

當(dāng)把非捕獲分組語(yǔ)法中的:換成>時(shí),就變成了原子分組(另一種非捕獲分組),可以進(jìn)一步提升性能。因?yàn)樵臃纸M會(huì)將分組內(nèi)部的回溯操作關(guān)閉。

環(huán)視

環(huán)視是一種非捕獲分組,它根據(jù)某個(gè)模式之前或者之后的內(nèi)容要求匹配其他模式。環(huán)視也稱為零寬度斷言。

環(huán)視分類 說(shuō)明 舉例
(?=分組) 正前瞻,匹配且要求緊隨其后內(nèi)容為分組匹配的內(nèi)容 a(?=b),匹配a并且后面堅(jiān)接著是b的字符串,可以匹配abc但是不匹配acb
(?!分組) 反前瞻,即對(duì)正前瞻含義取反,匹配且要求緊隨其后內(nèi)容不為分組匹配的內(nèi)容 a(?!b),匹配a并且后面堅(jiān)接著不是b的字符串,可以匹配acb但是不匹配abc
(?<=分組) 正后顧,即對(duì)正前瞻方向取反,匹配且要求緊挨著之前的內(nèi)容為分組匹配的內(nèi)容 (?<=a)b),匹配b并且前面緊挨著是a的字符串,可以匹配abc但是不匹配cbc
(?<!分組) 反后顧,即對(duì)正后顧含義取反,匹配且要求緊挨著之前的內(nèi)容不為分組匹配的內(nèi)容 (?<!a)b),匹配b并且前面緊挨著不是a的字符串,可以匹配cbc但是不匹配abc

條件匹配

(?(id/name)yes-pattern|no-pattern)
如果給定的 id 或 name 存在,將會(huì)嘗試匹配yes-pattern;否則就嘗試匹配no-pattern,no-pattern可選;
例如:email樣式匹配(<)?(\w+@\w+(?:\.\w+)+)(?(1)>|$),當(dāng)<存在時(shí),則最后要匹配>;否則匹配結(jié)束符$

參考

《學(xué)習(xí)正則表達(dá)式》
《正則表達(dá)式必知必會(huì)》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容