在編寫處理字符串的程序或網頁時,經常會有查找符合某些復雜規則的字符串的需要。正則表達式就是用於描述這些規則的工具口換句話說,正則表達式就是記錄文本規則的代碼。
正則表達式在unix/linux系統中得到廣泛的應用,強化了工具本身的功能。常見的UNIX下支持正則表達式的工具有:
》用於匹配文本行的grep工具族:
》用於改變輸入流的sed流編輯器(streamediter);
》用於處理字符串的語言,如awk, python, perl, tcl等語言;
》文件查看程序,或分頁程序,如mare. page, less等。
》文本編輯器,如ed, vi,emacs, vim等·
實例一
匹配當前存在 file單詞並且在這個單詞後還有一個file的句子
\bfile\b.*\bfile\b
Copy一段
假如你要找的是hi後面不遠處跟著一個Lucy,你應該用\bhi\b.*\bLucy\b。
這裡,.是另一個元字符,匹配除了換行符以外的任意字符。*同樣是元字符,不過它代表的不是字符,也不是位置,而是數量——它指定*前邊的內容可以連續重復使用任意次以使整個表達式得到匹配。因此,.*連在一起就意味著任意數量的不包含換行的字符。現在\bhi\b.*\bLucy\b的意思就很明顯了:先是一個單詞hi,然後是任意個任意字符(但不能是換行),最後是Lucy這個單詞。
換行符就是'\n',ASCII編碼為10(十六進制0x0A)的字符。
如果同時使用其它元字符,我們就能構造出功能更強大的正則表達式。比如下面這個例子:
0\d\d-\d\d\d\d\d\d\d\d匹配這樣的字符串:以0開頭,然後是兩個數字,然後是一個連字號“-”,最後是8個數字(也就是中國的電話號碼。當然,這個例子只能匹配區號為3位的情形)。
這裡的\d是個新的元字符,匹配一位數字(0,或1,或2,或……)。-不是元字符,只匹配它本身——連字符(或者減號,或者中橫線,或者隨你怎麼稱呼它)。
為了避免那麼多煩人的重復,我們也可以這樣寫這個表達式:0\d{2}-\d{8}。這裡\d後面的{2}({8})的意思是前面\d必須連續重復匹配2次(8次)。
如果需要更精確的說法,\b匹配這樣的位置:它的前一個字符和後一個字符不全是(一個是,一個不是或不存在)\w。
我們不是機器,總會犯錯誤。一般情況下,正則表達式不可能一次寫正確。這就需要我們不斷修改正則表達式,不斷通近那個正確的寫法,直到恰好達到我們想要的目的。
NOTE
歷史上曾經出現過3種grep,可以用於匹配文本。它們是:
Grep 最早的文本匹配程序。使用PQSIX支持的基本正則表達式(Basic Regular Expression, BRE )
Egrep 擴展的grep(Extend grep)。使用擴展正則表達式〔Extended Regular Expression, ERE )
Fgrep 快速grep( Fast grep)。這個版本用於匹配固定字符串而不是正則表達式。
在I942年發布的PDS1X標准中,3個prep版本合而為一,POSIX可以通過參數來支持多個正則表達式模式,無論是BRE還是ERE,fgrep和egrep還是可以在所有的unix/inux系統上使用,但是被標記為deprecated(不推薦〕
正則表達式是描述某種匹配規則的工具。
正則中有兩種字符一種基本字符(沒有任何意義),一種元字符(賦予了表達匹配的某些含義)
POSIXBRE和ERE都支持的meta字符
^
BRE,ERE
錨定行或者字符串的開始,如"^grep" 匹配所有以grep開頭的行。
BRE:僅在正則表達式結尾處具有特殊含義;
ERE:在正則表達式的任何地方都有特殊含義。
$
BRE,ERE
錨定行或者字符串的結束,如"grep$" 匹配所有以grep結束的行。
BRE:僅在正則表達式結尾處具有特殊含義;
ERE:在正則表達式的任何地方都有特殊含義。
.
BRE,ERE
匹配一個非換行的任何單個字符(除NUL)。
如:‘gr.p'匹配gr後加一個任意字符後,然後p
*
BRE,ERE
匹配其前的任何數目或沒有的單個字符,
例: . 表示任一字符, 則 .* 匹配任一字符的任意長度
[]
BRE,ERE
匹配方括號內的任一字符,其中可用連字符(-)指的連續字符的范圍
;^符號苦出現在方括號的第一個位置,則表示匹配不在列表中的任一字符,
POSIXBRE中才有的字符:
\{n,m\}
區間表達式,匹配在它前面的單個字符重現的次數區別。
\{n\}指重現n次;\{n,m\}指重現n至m次;
\( \)
保留空間,可以將最多9個獨立的子模式存儲在單個模式中。
如\(ab\).*\1 : 指匹配ab組合的兩次重現,中間可存在任意數目的字符。
\n
重復在\(與\)方括號內第n個子模式至此點的模式。
POSIXERE中才有的字符:
{n,m}
與BRE的\{n,m\}功能相同
+
匹配前面正則表達式的一個或多個擴展
?
匹配前面正則表達式的零個或一個擴展
|
匹配|符號前或後的正則表達式
( )
匹配方括號括起來的正則表達式群
Grep程序支持的meta字符plus
\<
錨定單詞的開始,如:“\<grep” 匹配以grep開頭的單詞的行
\>
錨定單詞的結束,
如:“grep\>”匹配包含以grep結尾的單詞的行
\w
匹配文字和數字字符.也就是[A-Za-z0-9],
如’G\w*p‘匹配以G後跟零個或多個文字或數字字符.然後是p
\W
\w的反之形式,匹配一個或多個非單詞字符,如點號、句號等
\b
單詞鎖定符,如:\bgrep\b只匹配grep
實例
//只顯示以a開頭的文件
[houchangren@ebsdi-23260-oozie shell]$ ls |grep '^a' add.sh a.sh
//顯示a開頭的文件中包含hadoop的行
[houchangren@ebsdi-23260-oozie shell]$grep 'hadoop' a* a.sh:HADOOP_IN_PATH="/usr/lib/hadoop/bin/hadoop" a.sh:HADOOP=$HADOOP_HOME/bin/hadoop
//顯示a.sh文件中包含hadoop的行
[houchangren@ebsdi-23260-oozie shell]$grep 'hadoop' a.sh HADOOP_IN_PATH="/usr/lib/hadoop/bin/hadoop" HADOOP=$HADOOP_HOME/bin/hadoop
//顯示連續五個a-z的字符在一行的行
[houchangren@ebsdi-23260-oozie shell]$ grep'[a-z]\{5\}' a.sh HADOOP_IN_PATH="/usr/lib/hadoop/bin/hadoop" HADOOP_DIR=`dirname "$HADOOP_IN_PATH"`/.. HADOOP=$HADOOP_HOME/bin/hadoop HADOOP_VERSION=$($HADOOP version | awk '{if(NR == 1) {print $2;}}');
//顯示如果test被匹配,es就被存儲到內存中,並標記為1.然後搜索任意個字符(.*),這些字符後面跟著另外一個es (\1),找到就顯示該行。\1是取占位括號中的值。
[houchangren@ebsdi-23260-oozie shell]$ cata.txt I'm test; test; so you don't worry! [houchangren@ebsdi-23260-oozie shell]$ grep't\(es\)t.*\1' a.txt I'm test; test;
為了在不同國家的字符編碼中保持一至,POSIX(The PortableOperating System Interface)增加了特殊的字符類,如[:alnum:]是A-Za-z0-9的另·個寫法。要把它們放到[]號內才能成為正則表達式,如[A-Za-z0-9]或[[:alnum: ]] 在Linux下的grep除fgrap外,都支持POSIX的字符類。方括號表達式除了上面提到的字符外,還支持其他的組成形式:
1. posix字符集
[:alnum:]
文字數字字符
[:alpha:]
文字字符
[:blank:]
空格與定位字符
[:cntrl:]
控制字符
[:digit:]
數字字符
[:graph:]
非空格字符
[:lower:]
小寫字母字符
[:print:]
可顯示的字符
[:punct:]
標點符號字符
[:space:]
空格字符
[:upper:]
大寫字母字符
[:xdigit:]
16進制數字
2. 排序符號
指將多個字符視為一個符號,如[.cn.]即將cn視為一個符號
3. 等價字符集
認為多個字符相等,如[=e=]在法文的locale裡,可匹配於多種與e相似的字符
正則表達式允許將POSIX字符集與其他字符集混用。如[[:alpha:]!]匹配任意一個英文字母或者感歎號(!)。
//匹配或者數字或者!
[houchangren@ebsdi-23260-oozie shell]$ grep -E'[[:digit:]!]+' a.txt
so you don't worry!
匹配單個字符的方式有4種:一般字符、轉義的meta字符、.(點號)meta字符,和方括號表達式。
1. 一般字符
例如:abc 就是 匹配abc
2. 轉義的meta字符
例如:\*匹配 * \[\] 匹配[]
3. .(點號)字符
例如: .bc 匹配 abc,dbc等等
4. 方括號表達式
例如:[cC]hina 只匹配 china 和Chnia
[^abc]d 匹配除了abc之外的任何小寫字母
BRE的運算優先
運算符
含義
[..][==][::]
方括號符號
\meta
轉義的meta字符
[]
方括號表達式
\(\)\n
後向引用表達式
*\{\}
區間表達式和星號表達式
無符號
連續
^&
錨點
ERE的運算優先
運算符
含義
[..][==][::]
方括號符號
\meta
轉義的meta字符
[]
方括號表達式
()
分組
*+?{}
重置前置的正則表達式
無符號
連續
^&
錨點
|
交替
1. 向後引用
BRE中提供了一種機制名為“後向引用”backreferences,含義是:匹配的是之前正則表達式選定的部分。我們使用\1一\19來引用之前選定的模式,使用\(和\)括起想要之後引用的部分。
例如:
\(go\).*\1 匹配一行中前後出現兩個go
2. 交替
交替是ERE才一有的特性。當使用方括號表達式時,表示可以“匹配這個字符,或者那個字符”,但是無法“匹配這個字符序列或那個字符序列”。當我們需要這個功能時,在ERE中,就用到交替.交替是在不同序列之間用管道符號隔開。例如,you|me匹配you或者me.
交替字符可以和管道符號一樣,在一個正則表達式中使用多個來提供多種選擇。因為交替字符的優先級最低,所以會一直擴展到新的交替字符,或正則表達式結束為止。
3. 分組
在BRE中,我們使用一些meta字符修飾前置字符,匹配重復的情況。但是這樣的操作僅僅
針對單個字符。在ERE中,分組功能能夠計meta字符修飾前置字符串。分組符號就是使用(和)
將式子括起來。例如〔go)+匹配一個或多個連續的go.
在使用交替時,分組就非常有用。例如:(Lily|Lucy) will visit my house today.在這個正則表達式中,分組限定了訪問我家的是Lily或者是Lucy。
正則表達式之所以如此重要,一個原因是許多程序(包括UNIX/linux下的,和Win下的)
都使用正則表達式為自己提供擴展,以支持更強大的功能。
正則表達式的風格有兩種,BRE和ERE,這是歷史遺留的產物。egrep風格的正則表達式在
UNIX開發的早期就已經出現,但是Linux的創始人KenThompson覺得不需要在ed編輯器中使
用這樣全方位的正則表達式支持,ed的標准後來演化為BRE。
ed又成為grep和sed的基礎,故此。grep和sed支持的正則表達式類型是BRE。在pre-V7
時期,egrep被發明出來,egrep是使用的ERE風格正則。但是,當egrep, grep, fgrep合並成
個grep程序時,grep就同時支持不同風格的正則表達式〔通過一E選項支持ERE)o與此同時,egrep
雖然被從POSIX標准中踢出,但是許多UNIX/LINUX發行版本仍然文持egrep命令,而且許多歷
史遺留腳本仍然在使用egrep,雖然標准做法應該是grep -E
使用ERE風格n則表達式的部分程序有egrep, awk和lex. lex是一個詞法分析器構建程序,
除了特殊情況下,很少在shell編程中用到。
除了前面提到的BRE和ERE這兩種標准正則表達式支持外,許多程序根據需求提供正則表
達式的語法擴展。最常見的擴展是\<和\>,分別匹配單詞開頭和單詞結尾。
單詞的開頭有兩種情況,一種是位於行的起始位置,一種是緊跟在非一單詞組成字符後面;同樣,單詞的結尾也是兩種情況;行的末尾和尾隨一個非單詞組成字符。
GUN支持額外的正則表達式運算符
含義
\w
匹配任何單詞組成字符,等同[[:alnum:]]
\W
匹配任何非單組成字符,等同[^[:alnum:]]
\<\>
匹配單詞的開頭和結尾
\b
匹配單詞開頭和結尾處所找到的空字符o \bword就等同\<word\>
\B
匹配兩個單詞組成字符間的空字符串
\’\`
分別匹配emacs緩沖區的開頭和結尾。GNU程序通常將它們視為與^和S同義
研究羅馬數字
有點腦袋大,那天有心情在研究吧。
解析電話號碼實例
echo '80055512121234' | grep -E"^[[:digit:]]{3}[^[:digit:]]*[[:digit:]]{3}[^[:digit:]]*[[:digit:]]{4}[^[:digit:]]*[[:digit:]]*$" echo '800-555-1212' | grep -E"^[[:digit:]]{3}[^[:digit:]]*[[:digit:]]{3}[^[:digit:]]*[[:digit:]]{4}[^[:digit:]]*[[:digit:]]*$" echo '800-555-1212-1234' | grep -E"^[[:digit:]]{3}[^[:digit:]]*[[:digit:]]{3}[^[:digit:]]*[[:digit:]]{4}[^[:digit:]]*[[:digit:]]*$" echo 'work 1-(800) 555.1212 #1234' | grep-E "[[:digit:]]{3}[^[:digit:]]*[[:digit:]]{3}[^[:digit:]]*[[:digit:]]{4}[^[:digit:]]*[[:digit:]]*$"
表達式解析一下:
[[:digit:]]{3} 三位數字
[^[:digit:]]* 非數字的任何東西(或者沒有)
[[:digit:]]{3} 三位數字
[^[:digit:]]* 非數字的任何東西(或者沒有)
[[:digit:]]{4} 四位數字
[^[:digit:]]* 非數字的任何東西(或者沒有)
[[:digit:]]* 數字(可沒有)