簡(jiǎn)介
推薦閱讀:Jeffrey Friedl 《精通正則表達(dá)式(第3版)》,本文是該書(shū)的讀書(shū)筆記 。
定義
正則表達(dá)式:regular expression, regex,是用來(lái)描述或者匹配一系列符合某個(gè)句法規(guī)則的字符串的單個(gè)字符串。正則表達(dá)式這個(gè)概念最初是由Unix中的工具軟件(例如sed和grep)普及開(kāi)的。
分類
- BREs, 基本的正則表達(dá)式(Basic Regular Expression)
- EREs, 擴(kuò)展的正則表達(dá)式(Extended Regular Expression)
- PREs, Perl 的正則表達(dá)式(Perl Regular Expression)
Linux常用文本工具
只有掌握了正則表達(dá)式,才能全面地掌握 Linux 下的常用文本工具(例如:grep、egrep、GUN sed、 Awk 等)的用法。
grep, egrep
1)grep 支持:BREs、EREs、PREs 正則表達(dá)式
- grep 指令后不跟任何參數(shù),則表示要使用 ”BREs“
- grep 指令后跟 ”-E" 參數(shù),則表示要使用 “EREs“
- grep 指令后跟 “-P" 參數(shù),則表示要使用 “PREs"
2)egrep 支持:EREs、PREs 正則表達(dá)式
- egrep 指令后不跟任何參數(shù),則表示要使用 “EREs”
- egrep 指令后跟 “-P" 參數(shù),則表示要使用 “PREs"
3)grep 與 egrep 正則匹配文件,處理文件方法
a. grep 與 egrep 的處理對(duì)象:文本文件
b. grep 與 egrep 的處理過(guò)程:查找文本文件中是否含要查找的 “關(guān)鍵字”(關(guān)鍵字可以是正則表達(dá)式) ,如果含有要查找的 ”關(guān)健字“,那么默認(rèn)返回該文本文件中包含該”關(guān)健字“的該行的內(nèi)容,并在標(biāo)準(zhǔn)輸出中顯示出來(lái),除非使用了“>" 重定向符號(hào),
c. grep 與 egrep 在處理文本文件時(shí),是按行處理的
sed
1)sed 文本工具支持:BREs、EREs
- sed 指令默認(rèn)是使用"BREs"
- sed 命令參數(shù) “-r ” ,則表示要使用“EREs"
2)sed 功能與作用
a. sed 處理的對(duì)象:文本文件
b. sed 處理操作:對(duì)文本文件的內(nèi)容進(jìn)行 --- 查找、替換、刪除、增加等操作
c. sed 在處理文本文件的時(shí)候,也是按行處理的
Awk(gawk)
1)Awk 文本工具支持:EREs
- awk 指令默認(rèn)是使用 “EREs"
2)Awk 文本工具處理文本的特點(diǎn)
a. awk 處理的對(duì)象:文本文件
b. awk 處理操作:主要是對(duì)列進(jìn)行操作
匹配單個(gè)字符
Ben是一個(gè)正則表達(dá)式。正則表達(dá)式可以包含純文本(甚至可以只包含純文本)。
匹配純文本
文本
Hello, my name is Ben. Please visit my website at http://www./.
正則表達(dá)式
Ben
結(jié)果
匹配任意字符
. 字符可以匹配任何一個(gè)單個(gè)的字符。
文本
sales1.xls
sales2.xls
sales3.xls
na1.xls
na2.xls
orders3.xls
apac1.xls
europe2.xls
正則表達(dá)式
sales.
結(jié)果
匹配一組字符
匹配多個(gè)字符中的某一個(gè)
sales1.xls
sales2.xls
sales3.xls
na1.xls
na2.xls
sa1.xls
ca1.xls
orders3.xls
apac1.xls
europe2.xls
正則表達(dá)式
[ns]a.\.xls
結(jié)果
使用字符區(qū)間
在使用正則表達(dá)式的時(shí)候,會(huì)頻繁地用到一些字符區(qū)間(0-9、A-Z)。為了簡(jiǎn)化字符區(qū)間的定義,正則表達(dá)式提供一個(gè)特殊的元字符:- 作為連字符。
正則表達(dá)式
[ns]a[0-9]\.xls
結(jié)果
匹配任何一個(gè)字母(無(wú)論大小寫(xiě))或數(shù)字
[A-Za-z0-9]
取非匹配
字符集合通常用來(lái)指定一組必須匹配其中之一的字符。但是在某些場(chǎng)合下,我們需要反過(guò)來(lái)做,給出一組不需要得到的字符。換句話說(shuō):除了那個(gè)字符集合里的字符,其他字符都可以匹配 ,使用字符^ 。
正則表達(dá)式
[ns]a[^0-9]\.xls
結(jié)果:上述輸入沒(méi)有結(jié)果,因?yàn)闆](méi)有匹配字符串。
小結(jié)
元字符[ 和] 用來(lái)定義一個(gè)字符集合,必須匹配該集合里的字符之一。定義一個(gè)字符集合的具體方法有兩種:
- 把所有的字符都列舉出來(lái)
- 利用元字符
- 以字符區(qū)間的方式給出
字符集合可以用元字符^ 來(lái)求非,這將把給定的字符集合強(qiáng)行排除在匹配操作外——除了該字符集合里的字符,其他字符都可以被匹配。
使用元字符
對(duì)特殊字符進(jìn)行轉(zhuǎn)義
元字符是一些在正則表達(dá)式里有特殊含義的字符。英文句號(hào). 是一個(gè)元字符,用來(lái)匹配任何一個(gè)單個(gè)字符;左方括號(hào)[ 也是一個(gè)元字符,表示一個(gè)字符集合的開(kāi)始。
因?yàn)樵址谡齽t表達(dá)式中有特殊的含義,所以這些字符無(wú)法代表它們本身。需要在元字符的前面加上一個(gè)反斜杠 進(jìn)行轉(zhuǎn)義——轉(zhuǎn)義序列\. 將匹配. 本身。
文本
\home\ben\sales
正則表達(dá)式
\
結(jié)果
匹配空白字符
在進(jìn)行正則表達(dá)式搜索的時(shí)候,我們經(jīng)常會(huì)遇到需要對(duì)原始文本里的非打印空白字符進(jìn)行匹配的情況。比如找出所有的制表符或換行符,這類字符很難被直接輸入到正則表達(dá)式里,可以用如下的特殊元字符來(lái)輸入。
元字符 |
說(shuō)明 |
[\b] |
回退(并刪除)一個(gè)字符(Backspace鍵) |
\f |
換頁(yè)符 |
\n |
換行符 |
\r |
回車符 |
\t |
制表符 |
\v |
垂直制表符 |
文本
"101","Ben","Forta"
"102","Jim","James"
正則表達(dá)式
\r\n\r\n
結(jié)果
"101","Ben","Forta"
"102","Jim","James"
分析
\r\n 匹配一個(gè)“回車+換行”組合,Windows操作系統(tǒng)都把這個(gè)組合作為文本行的結(jié)束標(biāo)簽。使用正則表達(dá)式\r\n\r\n 進(jìn)行的搜索將匹配兩個(gè)連續(xù)的行尾標(biāo)簽,正是兩條記錄之間的空白行。
匹配文本結(jié)束標(biāo)簽
同時(shí)適用于Windows和Linux系統(tǒng)的正則表達(dá)式,應(yīng)該包含一個(gè)可選的\r 和一個(gè)必須被匹配的\n 。
匹配特定的字符類別
字符集合(匹配多個(gè)字符中的某一個(gè))是最常見(jiàn)的匹配形式,而一些常用的字符集合可以用特殊元字符 來(lái)替代。
匹配數(shù)字(非數(shù)字)
元字符 |
說(shuō)明 |
\d |
任何一個(gè)數(shù)字字符(等價(jià)于[0-9]) |
\D |
任何一個(gè)非數(shù)字字符(等價(jià)于[^0-9]) |
匹配字母和數(shù)字(非字母和數(shù)字)
元字符 |
說(shuō)明 |
\w |
任何一個(gè)字母數(shù)字字符或下劃線字符([a-zA-Z0-9_]) |
\W |
任何一個(gè)非字母數(shù)字字符或下劃線字符([^a-zA-Z0-9_]) |
文本
11213
A1C2E3
48075
M1B4F2
正則表達(dá)式
\w\d\w\d\w\d
結(jié)果
匹配空白字符(非空白字符)
另一種常見(jiàn)的字符類別是空白字符 。
元字符 |
說(shuō)明 |
\s |
任何一個(gè)空白字符(等價(jià)于[\f\n\r\t\v]) |
\S |
任何非一個(gè)空白字符(等價(jià)于[^\f\n\r\t\v]) |
小結(jié)
主要講解用來(lái)匹配特定字符(制表符、換行符)和用來(lái)匹配一個(gè)字符集合或字符類(數(shù)字、字母數(shù)字字符)的元字符。這些簡(jiǎn)短的元字符可以用來(lái)簡(jiǎn)化正則表達(dá)式模式。
重復(fù)匹配
有多少個(gè)匹配
需要一種能夠匹配多個(gè)字符的方法,可以通過(guò)幾個(gè)特殊的元字符來(lái)實(shí)現(xiàn)。
匹配一個(gè)或多個(gè)字符
要想匹配同一個(gè)字符(或字符集合)的多次重復(fù),只要簡(jiǎn)單地給這個(gè)字符(或字符集合)加上一個(gè)+ 字符作為后綴就可以了。+ 匹配一個(gè)或多個(gè)字符 (至少一個(gè),不匹配零個(gè)字符的情況)。
比如:a匹配a本身,a+將匹配一個(gè)或多個(gè)連續(xù)出現(xiàn)的a。
文本
Send personal email to ben@. For questions
about a book use support@. Feel
free to send unsolicited email to spam@.
正則表達(dá)式
\w+@\w+\.\w+
結(jié)果
這個(gè)模式把原始文本里的3個(gè)電子郵件地址全都正確匹配出來(lái)了。正則表達(dá)式中第一個(gè)\w+匹配一個(gè)或多個(gè)字母數(shù)字字符,再用第二個(gè)\w+匹配@后面的一個(gè)或多個(gè)字符,然后匹配一個(gè).字符(使用轉(zhuǎn)移序列.),最后用第三個(gè)\w+匹配電子郵件地址的剩余部分。
匹配零個(gè)或多個(gè)字符
+ 匹配一個(gè)或多個(gè)字符,但不匹配零個(gè)字符——+最少也要匹配一個(gè)字符。那么,如果你想匹配一個(gè)可有可無(wú)的字符——也就是該字符可以出現(xiàn)零次或多次的情況,你該怎么辦呢?
這種匹配需要用* 元字符來(lái)完成,把它放在一個(gè)字符(或一個(gè)字符集合)的后面,就可以匹配該字符(或字符集合)連續(xù)出現(xiàn)零次或多次的情況。
文本
Hello .ben@ is my email.
正則表達(dá)式
\w+[\w.]*@[\w.]+\.\w+
結(jié)果
\w+:負(fù)責(zé)匹配電子郵件地址中第一個(gè)字符(一個(gè)字母數(shù)字字符,但是不包括.)。
[\w.]*:負(fù)責(zé)匹配電子郵件第一個(gè)字符之后、@字符之前的所有字符——這個(gè)部分可以包含零個(gè)或多個(gè)字母數(shù)字字符和.字符。
匹配零個(gè)或一個(gè)字符
? 只能匹配一個(gè)字符(或字符集合)的零次或一次出現(xiàn),最多不超過(guò)一次。如果需要在一段文本里匹配某個(gè)特定的字符,而該字符可能出現(xiàn)、也可能不出現(xiàn),? 無(wú)疑是最佳的選擇。
文本
The URL is http://www./, to connect
securely use https://www./
正則表達(dá)式
https?://[\w./]+
結(jié)果
這個(gè)模式的開(kāi)頭部分是https? 。?在這里的含義是:前面的字符s要么不出現(xiàn),要么最多出現(xiàn)一次。
在Windows上使用模式\r\n\r\n 去匹配空白行,在Linux系統(tǒng)的正則表達(dá)式是\n\n 。同時(shí)適用于Windows和Linux系統(tǒng)的正則表達(dá)式應(yīng)該包含一個(gè)可選的\r和一個(gè)必須的\n。
[\r]?\n[\r]?\n
匹配的重復(fù)次數(shù)
正則表達(dá)式里的+ * ? 解決了許多問(wèn)題,但是光靠這些還不夠。比如:
- +和*匹配的字符個(gè)數(shù)沒(méi)有上限。我們無(wú)法為它們將匹配的字符個(gè)數(shù)設(shè)定一個(gè)最大值。
- +、*和?至少匹配零個(gè)或一個(gè)字符。我們無(wú)法為它們將匹配的字符個(gè)數(shù)另行設(shè)定一個(gè)最小值。
- 如果只使用+和*,我們無(wú)法把它們將匹配的字符個(gè)數(shù)設(shè)定為一個(gè)精確的數(shù)字。
為了解決這些問(wèn)題并且對(duì)重復(fù)性匹配有更多的控制,正則表達(dá)式語(yǔ)言提供了一個(gè)用來(lái)設(shè)定重復(fù)次數(shù) 的語(yǔ)法。重復(fù)次數(shù)要用{} 來(lái)給出——把數(shù)值寫(xiě)在它們之間。
為重復(fù)匹配次數(shù)設(shè)定一個(gè)區(qū)間
為重復(fù)匹配次數(shù)設(shè)定一個(gè)最小值和最大值,這種區(qū)間必須以{2, 4} 這樣的形式給出,含義是最少重復(fù)2次、最多重復(fù)4次。
文本
4/8/03
10-6-2004
2/2/2
01-01-01
正則表達(dá)式
\d{1,2}[-\/]\d{1,2}[-\/]\d{2,4}
結(jié)果
匹配“至少重復(fù)多少次”
{3,}表示至少重復(fù)3次,與之等價(jià)的說(shuō)法是“必須重復(fù)3次或更多次”。
防止過(guò)度匹配
文本
<B>AK</B> and <B>HI</B>
正則表達(dá)式
<[Bb]>.*</[Bb]>
結(jié)果
這個(gè)正則表達(dá)式匹配了所有字符,而不是預(yù)期的標(biāo)簽內(nèi)的內(nèi)容。為什么會(huì)這樣?因?yàn)?code>*和+ 都是所謂的貪婪型 元字符,它們?cè)谶M(jìn)行匹配時(shí)的行為模式是多多益善而不是適可而止的。
在不需要這種“貪婪行為”的時(shí)候該怎么辦?答案是使用這些元字符的“懶惰型”版本。懶惰型元字符的寫(xiě)法很簡(jiǎn)單,只要給貪婪型元字符加上一個(gè)? 后綴即可。
貪婪型元字符 |
懶惰型元字符 |
* |
*? |
+ |
+? |
{n,} |
{n,}? |
對(duì)于上面的例子,使用正則表達(dá)式
<[Bb]>.*?</[Bb]>
結(jié)果
小結(jié)
正則表達(dá)式的真正威力體現(xiàn)在重復(fù)次數(shù)匹配方面。
- +:匹配字符的一次或多次出現(xiàn)
- ?:匹配字符的0次或一次出現(xiàn)
- *:匹配字符的0次或多次出現(xiàn)
- {}:精確地設(shè)定重復(fù)次數(shù)
元字符分貪婪型 和懶惰型 兩種;在需要防止過(guò)度匹配的場(chǎng)合下,使用懶惰型 元字符來(lái)構(gòu)造你的正則表達(dá)式。
位置匹配
邊界
位置匹配用來(lái)解決在什么地方 進(jìn)行字符串匹配操作的問(wèn)題。例如使用cat 正則搜索文本,scatter 也會(huì)被匹配到,如果只是想搜索cat 這個(gè)單詞,就需要邊界。
單詞邊界
單詞邊界由限定符\b 指定,匹配一個(gè)單詞的開(kāi)始或結(jié)尾。\b匹配的是這樣的位置,這個(gè)位置位于一個(gè)能夠用來(lái)構(gòu)成單詞的字符(字母、數(shù)字和下劃線,也就是與\w相匹配的字符)和一個(gè)不能用來(lái)構(gòu)成單詞的字符(\W)之間。
如果不想匹配單詞邊界,使用\B 。
文本
The cat scattered his food.
正則表達(dá)式
\bcat\b
結(jié)果
字符串邊界
單詞邊界可以用來(lái)進(jìn)行與單詞有關(guān)的位置匹配(單詞的開(kāi)頭、單詞的結(jié)束、整個(gè)單詞)。字符串邊界有著類似的用途,用來(lái)進(jìn)行與字符串有關(guān)的位置匹配(字符串的開(kāi)頭、字符串的結(jié)束、整個(gè)字符串)。用來(lái)定義字符串邊界的元字符有兩個(gè):
- ^:定義字符串開(kāi)頭
- $:定義字符串結(jié)尾
文本
<?xml version="1.0" ?>
xmlns:blablabla
xmlns:blablabla
正則表達(dá)式
^\s*<\?xml.*\?>
結(jié)果
小結(jié)
正則表達(dá)式不僅可以用來(lái)匹配任意長(zhǎng)度的文本塊,還可以用來(lái)匹配出現(xiàn)在字符串中特定位置的文本。\b 用來(lái)指定一個(gè)單詞邊界(\B剛好相反)。^ 和$ 用來(lái)指定字符串邊界(字符串的開(kāi)頭和結(jié)束)。
使用子表達(dá)式
什么是子表達(dá)式
我們已經(jīng)知道了如何匹配一個(gè)字符的連續(xù)多次重復(fù)。比如\d+ 將匹配一個(gè)或多個(gè)數(shù)字字符,而https? 將匹配http或https。但是這兩個(gè)用來(lái)表明重復(fù)次數(shù)的元字符只作用于緊挨著它的前一個(gè)字符或元字符 。
子表達(dá)式是一個(gè)更大的表達(dá)式的一部分;把一個(gè)表達(dá)式劃分為一系列子表達(dá)式的目的是為了把那些子表達(dá)式當(dāng)作一個(gè)獨(dú)立的元素來(lái)使用。子表達(dá)式必須用() 括起來(lái)。
文本
Hello, my name is yano
I like 123
正則表達(dá)式
( ){2,}
結(jié)果
( ) 是一個(gè)子表達(dá)式,它是一個(gè)獨(dú)立的元素,緊跟在它后面的{2,}將作用于這個(gè)子表達(dá)式(而不僅僅是分號(hào))。
子表達(dá)式的嵌套
子表達(dá)式允許嵌套,多重嵌套的子表達(dá)式可以構(gòu)造出功能極其強(qiáng)大的正則表達(dá)式來(lái),但是難免會(huì)讓模式變得難以閱讀和理解。
如何匹配一個(gè)IP地址 ?
一個(gè)合法的IP地址里的各組數(shù)字必須滿足:
- 任何一個(gè)1位或2位數(shù)字
- 任何一個(gè)以1開(kāi)頭的3位數(shù)字
- 任何一個(gè)以2開(kāi)頭、第2位數(shù)字在0~5之間的3位數(shù)字
- 任何一個(gè)以25開(kāi)頭、第3位數(shù)字在0~5之間的3位數(shù)字
正則表達(dá)式
(((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))\.){3}((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))
小結(jié)
子表達(dá)式的作用是把同一個(gè)表達(dá)式的各個(gè)相關(guān)部分組合在一起。子表達(dá)式必須用() 來(lái)定義。子表達(dá)式的常見(jiàn)用途包括:對(duì)重復(fù)次數(shù)元字符的作用對(duì)象作出精確的設(shè)定和控制、對(duì)| 操作符的OR條件作出精確的定義等等。
回溯引用:前后一致匹配
回溯引用有什么用
首先看一個(gè)例子。HTML程序員經(jīng)常使用標(biāo)題標(biāo)簽(<H1> 到<H6> ,以及配對(duì)的結(jié)束標(biāo)簽)來(lái)定義和排版Web頁(yè)面里的標(biāo)題文字。假設(shè)需要找到某個(gè)Web頁(yè)面的所有標(biāo)題文字,不管它的級(jí)別是多少。
文本
<BODY>
<H1>Welcom to my Homepage</H1>
Content is divided into two sections:
<H2>ColdFusion</H2>
Happy Fish
<H2>Wireless</H2>
EXIT
</BODY>
正則表達(dá)式
<[hH]1>.*</[hH]1>
結(jié)果
模式<[hH]1>.*</[hH]1> 只能匹配一級(jí)標(biāo)題,但是如何才能匹配任意級(jí)別的標(biāo)題呢?如果使用一個(gè)字符集合來(lái)代替1,如下所示:
正則表達(dá)式
<[hH][1-6]>.*?</[hH][1-6]>
結(jié)果
這個(gè)模式匹配任何一級(jí)標(biāo)題的開(kāi)始標(biāo)簽和結(jié)束標(biāo)簽,但是匹配還是會(huì)有問(wèn)題,如果一個(gè)HTML的文本有問(wèn)題,<H2> 開(kāi)始標(biāo)簽對(duì)應(yīng)的結(jié)束標(biāo)簽是</H3> 怎么辦?如下所示:
文本
<BODY>
<H1>Welcom to my Homepage</H1>
Content is divided into two sections:
<H2>ColdFusion</H2>
Happy Fish
<H2>Wireless</H3>
EXIT
</BODY>
正則表達(dá)式
<[hH][1-6]>.*?</[hH][1-6]>
結(jié)果
在這個(gè)例子中,原始文本里有一個(gè)標(biāo)題是以<H2> 開(kāi)頭、以<H3> 結(jié)束的。這顯然是一個(gè)不合法的標(biāo)題,但是它與我們所使用的模式匹配上了。出現(xiàn)這種情況的根源是這個(gè)模式的第2部分對(duì)模式的第1部分毫無(wú)所知 。要想徹底解決這個(gè)問(wèn)題,就只能求助于回溯引用。
回溯引用匹配
對(duì)于上述文本,使用正則表達(dá)式
<[hH]([1-6])>.*?</[hH]\1>
結(jié)果
并沒(méi)有匹配錯(cuò)誤標(biāo)簽,因?yàn)槭褂昧嘶厮菀?。這次用() 把[1-6] 括了起來(lái),使它成為了一個(gè)自表達(dá)式 。這樣我們就可以用來(lái)匹配標(biāo)題結(jié)束標(biāo)簽的</[Hh]\1> 用\1 來(lái)引用這個(gè)自表達(dá)式。自表達(dá)式([1-6]) 匹配數(shù)字1~6,\1 只能匹配與之相同的數(shù)字。這樣一來(lái),<H2>Wireless</H3> 就不會(huì)被匹配到了。
回溯引用在替換操作中的應(yīng)用
到目前為止,博客介紹的正則表達(dá)式都是用來(lái)執(zhí)行搜索的,即在一段文本里查找特定的內(nèi)容。但是我們所編寫(xiě)的絕大多數(shù)正則表達(dá)式模式也可以用來(lái)搜索文本 ,但是還可以用來(lái)完成各種復(fù)雜的替換操作 。正則表達(dá)式更適用于復(fù)雜的替換,尤其是需要使用回溯引用的場(chǎng)合。
假如我們需要把原始文本里的電子郵件地址全都轉(zhuǎn)換為可點(diǎn)擊的鏈接,該怎么辦?
文本
Hello, ben@ is my email address.
正則表達(dá)式
(\w+[\w.]*@[\w\.]+\.\w+)
替換
<A HREF="mailto:$1">$1</A>
結(jié)果
Hello, <A HREF="mailto:ben@">ben@</A> is my email address.
替換操作需要用到兩個(gè)正則表達(dá)式:一個(gè)用來(lái)給出搜索模式,另一個(gè)用來(lái)給出匹配文本的替換模式?;厮菀每梢?code>跨模式使用,在第一個(gè)模式里被匹配的子表達(dá)式可以用在第二個(gè)模式里。這次正則表達(dá)式加了一對(duì)() ,把它變成了一個(gè)子表達(dá)式,這樣被匹配到的文本就可以用在替換模式里了。<A HREF="mailto:$1">$1</A> 使用了兩次被匹配的子表達(dá)式($1 )。
大小寫(xiě)轉(zhuǎn)換
用來(lái)進(jìn)行大小寫(xiě)轉(zhuǎn)換的元字符
元字符 |
說(shuō)明 |
\E |
結(jié)束\L或\U轉(zhuǎn)換 |
\S |
把下一個(gè)字符轉(zhuǎn)換為小寫(xiě)) |
\L |
把\L到\E之間的字符全部轉(zhuǎn)換為小寫(xiě) |
\u |
把下一個(gè)字符轉(zhuǎn)換為大寫(xiě) |
\U |
把\U到\E之間的字符全部轉(zhuǎn)換為大寫(xiě) |
\l和\u只能把下一個(gè)字符(或子表達(dá)式) 轉(zhuǎn)換為小寫(xiě)或大寫(xiě)。\L和\U將它后面的所有字符轉(zhuǎn)換為小寫(xiě)或大寫(xiě),直到遇到\E為止。
下面將一級(jí)標(biāo)題的標(biāo)題文字轉(zhuǎn)換為大寫(xiě):
文本
<BODY>
<H1>Welcom to my Homepage</H1>
Content is divided into two sections:
<H2>ColdFusion</H2>
Happy Fish
<H2>Wireless</H3>
EXIT
</BODY>
正則表達(dá)式
(<[Hh]1>)(.*?)(</[Hh]1>)
替換
$1\U$2\E$3
結(jié)果
<BODY>
<H1>WELCOM TO MY HOMEPAGE</H1>
Content is divided into two sections:
<H2>ColdFusion</H2>
Happy Fish
<H2>Wireless</H3>
EXIT
</BODY>
小結(jié)
子表達(dá)式 用來(lái)定義字符或表達(dá)式的集合。除了可以用在重復(fù)匹配操作 以外,還可以在模式的內(nèi)部 被引用,這種引用被稱為回溯引用 ?;厮菀迷?code>文本匹配和文本替換 操作里非常有用。
前后查找
有時(shí)候需要正則表達(dá)式標(biāo)記要匹配的文本的位置 (而不僅僅是文本本身)。這就引出了前后查找(lookaround,對(duì)某一位置的前后內(nèi)容進(jìn)行查找)的概念。
前后查找
我們現(xiàn)在要把一個(gè)Web頁(yè)面的頁(yè)面標(biāo)題提取出來(lái)。HTML頁(yè)面標(biāo)題是出現(xiàn)在<TITLE> 和</TITLE> 標(biāo)簽之間的文字。而這對(duì)標(biāo)簽又必須嵌在HTML代碼的<HEAD> 部分里。
文本
<HEAD>
<TITLE>Ben Forta's Homepage</TITLE>
</HEAD>
正則表達(dá)式
<TITLE>.*</TITLE>
結(jié)果
但是這個(gè)模式的效果不夠理想,因?yàn)橹挥?code>頁(yè)面標(biāo)題才是我們需要的。我們現(xiàn)在需要一種模式,它包含的匹配本身并不返回,而是用于確定正確的匹配位置,它并不是匹配結(jié)果的一部分——前后查找 。
向前查找
向前查找指定了一個(gè)必須匹配,但不在結(jié)果中返回的模式 。向前查找實(shí)際上就是一個(gè)子表達(dá)式,從語(yǔ)法上看,一個(gè)向前查找模式其實(shí)就是一個(gè)以?= 開(kāi)頭的子表達(dá)式,需要匹配的文本跟在= 后面。
我們來(lái)看一個(gè)例子。例子里的原始文本是一些URL地址,現(xiàn)在需要把它們的協(xié)議名部分提取出來(lái)。
文本
http://www./
https://mail./
ftp://ftp./
正則表達(dá)式
.+(?=:)
結(jié)果
在上面列出的URL地址里,協(xié)議名和主機(jī)名之間以一個(gè): 分隔。模式.+ 匹配任意文本(第一個(gè)匹配是http),子表達(dá)式(?=:) 匹配: 。注意,被匹配到的: 并沒(méi)有出現(xiàn)在最終的匹配結(jié)果里;我們用?= 向正則表達(dá)式引擎表明只要找到: 就行了,不要把它包括在最終的匹配結(jié)果里——用術(shù)語(yǔ)來(lái)講,就是“不消費(fèi)”它。
向后查找
?= 向前查找,查找出現(xiàn)在匹配文本之后的字符,但不消費(fèi)這個(gè)字符
?<= 向后查找,查找出現(xiàn)在匹配文本之后的字符,但不消費(fèi)這個(gè)字符
把向前查找和向后查找結(jié)合起來(lái)
文本
<HEAD>
<TITLE>Ben Forta's Homepage</TITLE>
</HEAD>
正則表達(dá)式
(?<=<TITLE>).*
結(jié)果
(?<=<TITLE>) 是一個(gè)向后查找操作,匹配但不消費(fèi)<TITLE> ;(?=</TITLE>) 是一個(gè)向前查找操作,匹配但不消費(fèi)</TITLE> 。
對(duì)前后查找取非
向前查找和向后查找通常用來(lái)匹配文本,其目的是為了確定將被返回為匹配結(jié)果的文本的位置。這種用法被稱為正前向查找 和正后向查找 。正 指的是尋找匹配的事實(shí)。
前后查找還有一種不太常見(jiàn)的用法叫負(fù)前后查找 ,指的是不與給定模式相匹配的文本。前后查找必須用! 來(lái)取非,替換掉= 。各種前后查找操作符如下表所示:
操作符 |
說(shuō)明 |
(?=) |
正向前查找 |
(?!) |
負(fù)向前查找 |
(?<=) |
正前后查找 |
(?<!) |
負(fù)向后查找 |
小結(jié)
有了向后查找,我們就可以對(duì)最終的匹配結(jié)果包含且只包含哪些內(nèi)容,做出更精確的控制。前后查找操作是我們可以利用子表達(dá)式來(lái)指定文本匹配操作的發(fā)生位置,并收到只匹配不消費(fèi)的效果。
公眾號(hào)
coding 筆記、點(diǎn)滴記錄,以后的文章也會(huì)同步到公眾號(hào)(Coding Insight)中,希望大家關(guān)注_
代碼和思維導(dǎo)圖在 GitHub 項(xiàng)目中,歡迎大家 star!
本文由博客一文多發(fā)平臺(tái) OpenWrite 發(fā)布!
|