Linux.Shell編程筆記-Regex

來源:互聯網
上載者:User

第四章 Regex什麼是Regex

在編寫處理字串的程式或網頁時,經常會有尋找符合某些複雜規則的字串的需要。Regex就是用於描述這些規則的工具口換句話說,Regex就是記錄文本規則的代碼。

Regex的廣泛應用

Regex在unix/linux系統中得到廣泛的應用,強化了工具本身的功能。常見的UNIX下支援Regex的工具有:

》用於匹配文本行的grep工具族:

》用於改變輸入資料流的sed流編輯器(streamediter);

》用於處理字串的語言,如awk, python, perl, tcl等語言;

》檔案查看程式,或分頁程式,如mare. page, less等。

》文字編輯器,如ed, vi,emacs, vim等·

如何學習Regex

執行個體一

匹配當前存在 file單詞並且在這個單詞後還有一個file的句子

\bfile\b.*\bfile\b

Copy一段

假如你要找的是hi後面不遠處跟著一個Lucy,你應該用\bhi\b.*\bLucy\b。

這裡,.是另一個元字元,匹配除了分行符號以外的任一字元。*同樣是元字元,不過它代表的不是字元,也不是位置,而是數量——它指定*前邊的內容可以連續重複使用任意次以使整個運算式得到匹配。因此,.*連在一起就意味著任意數量的不包含換行的字元。現在\bhi\b.*\bLucy\b的意思就很明顯了:先是一個單詞hi,然後是任意個任一字元(但不能是換行),最後是Lucy這個單詞。

分行符號就是'\n',ASCII編碼為10(十六進位0x0A)的字元。

如果同時使用其它元字元,我們就能構造出功能更強大的Regex。比如下面這個例子:

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。

如何實踐Regex

我們不是機器,總會犯錯誤。一般情況下,Regex不可能一次寫正確。這就需要我們不斷修改Regex,不斷通近那個正確的寫法,直到恰好達到我們想要的目的。

NOTE

曆史上曾經出現過3種grep,可以用於匹配文本。它們是:

Grep 最早的文本匹配程式。使用PQSIX支援的基本Regex(Basic Regular Expression, BRE )

Egrep 擴充的grep(Extend grep)。使用擴充Regex〔Extended Regular Expression, ERE )

Fgrep 快速grep( Fast grep)。這個版本用於匹配固定字串而不是Regex。

在I942年發布的PDS1X標準中,3個prep版本合而為一,POSIX可以通過參數來支援多個Regex模式,無論是BRE還是ERE,fgrep和egrep還是可以在所有的unix/inux系統上使用,但是被標記為deprecated(不推薦〕

正則基礎元字元

Regex是描述某種匹配規則的工具。

正則中有兩種字元一種基底字元(沒有任何意義),一種元字元(賦予了表達匹配的某些含義)

POSIXBRE和ERE都支援的meta字元

^

BRE,ERE

錨定行或者字串的開始,如"^grep" 匹配所有以grep開頭的行。
BRE:僅在Regex結尾處具有特殊含義;
ERE:在Regex的任何地方都有特殊含義。

$

BRE,ERE

錨定行或者字串的結束,如"grep$" 匹配所有以grep結束的行。
BRE:僅在Regex結尾處具有特殊含義;
ERE:在Regex的任何地方都有特殊含義。

.

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\}功能相同

+

匹配前面Regex的一個或多個擴充

?

匹配前面Regex的零個或一個擴充

|

匹配|符號前或後的Regex

( )

匹配方括弧括起來的Regex群

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.sha.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.shHADOOP_IN_PATH="/usr/lib/hadoop/bin/hadoop"HADOOP=$HADOOP_HOME/bin/hadoop 

//顯示連續五個a-z的字元在一行的行

[houchangren@ebsdi-23260-oozie shell]$ grep'[a-z]\{5\}' a.shHADOOP_IN_PATH="/usr/lib/hadoop/bin/hadoop" HADOOP_DIR=`dirname "$HADOOP_IN_PATH"`/..HADOOP=$HADOOP_HOME/bin/hadoopHADOOP_VERSION=$($HADOOP version | awk '{if(NR == 1) {print $2;}}');

//顯示如果test被匹配,es就被儲存到記憶體中,並標記為1.然後搜尋任意個字元(.*),這些字元後面跟著另外一個es (\1),找到就顯示該行。\1是取佔位括弧中的值。

[houchangren@ebsdi-23260-oozie shell]$ cata.txtI'm test; test;so you don't worry![houchangren@ebsdi-23260-oozie shell]$ grep't\(es\)t.*\1' a.txtI'm test; test;

為了在不同國家的字元編碼中保持一至,POSIX(The PortableOperating System Interface)增加了特殊的字元類,如[:alnum:]是A-Za-z0-9的另·個寫法。要把它們放到[]號內才能成為Regex,如[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相似的字元

Regex允許將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字元

[]

方括號運算式

()

分組

*+?{}

重設前置的Regex

無符號

連續

^&

錨點

|

交替

更多差異

1. 反向參考
BRE中提供了一種機制名為“後向引用”backreferences,含義是:匹配的是之前Regex選定的部分。我們使用\1一\19來引用之前選定的模式,使用\(和\)括起想要之後引用的部分。

例如:

\(go\).*\1 匹配一行中前後出現兩個go

2. 交替
交替是ERE才一有的特性。當使用方括號運算式時,表示可以“匹配這個字元,或者那個字元”,但是無法“匹配這個字元序列或那個字元序列”。當我們需要這個功能時,在ERE中,就用到交替.交替是在不同序列之間用管道符號隔開。例如,you|me匹配you或者me.

交替字元可以和管道符號一樣,在一個Regex中使用多個來提供多種選擇。因為交替字元的優先順序最低,所以會一直擴充到新的交替字元,或Regex結束為止。

3. 分組

在BRE中,我們使用一些meta字元修飾前置字元,匹配重複的情況。但是這樣的操作僅僅

針對單個字元。在ERE中,分組功能能夠計meta字元修飾前置字串。分組符號就是使用(和)

將式子括起來。例如〔go)+匹配一個或多個連續的go.

在使用交替時,分組就非常有用。例如:(Lily|Lucy) will visit my house today.在這個Regex中,分組限定了訪問我家的是Lily或者是Lucy。

Regex的應用

Regex之所以如此重要,一個原因是許多程式(包括UNIX/linux下的,和Win下的)

都使用Regex為自己提供擴充,以支援更強大的功能。

Regex的風格有兩種,BRE和ERE,這是曆史遺留的產物。egrep風格的Regex在

UNIX開發的早期就已經出現,但是Linux的創始人KenThompson覺得不需要在ed編輯器中使

用這樣全方位的Regex支援,ed的標準後來演化為BRE。

ed又成為grep和sed的基礎,故此。grep和sed支援的Regex類型是BRE。在pre-V7

時期,egrep被發明出來,egrep是使用的ERE風格正則。但是,當egrep, grep, fgrep合并成

個grep程式時,grep就同時支援不同風格的Regex〔通過一E選項支援ERE)o與此同時,egrep

雖然被從POSIX標準中踢出,但是許多UNIX/LINUX發行版本仍然文持egrep命令,而且許多曆

史遺留指令碼仍然在使用egrep,雖然標準做法應該是grep -E

使用ERE風格n則運算式的部分程式有egrep, awk和lex. lex是一個詞法分析器構建程式,

除了特殊情況下,很少在shell編程中用到。

擴充

除了前面提到的BRE和ERE這兩種標準Regex支援外,許多程式根據需求提供正則表

達式的文法擴充。最常見的擴充是\<和\>,分別匹配單詞開頭和單詞結尾。

單詞的開頭有兩種情況,一種是位於行的起始位置,一種是緊跟在非一單片語成字元後面;同樣,單詞的結尾也是兩種情況;行的末尾和尾隨一個非單片語成字元。

GUN支援額外的Regex運算子

 

含義

\w

匹配任何單片語成字元,等同[[:alnum:]]

\W

匹配任何非單組成字元,等同[^[:alnum:]]

\<\>

匹配單詞的開頭和結尾

\b

匹配單詞開頭和結尾處所找到的Null 字元o \bword就等同\<word\>

\B

匹配兩個單片語成字元間的Null 字元串

\’\`

分別匹配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:]]* 數字(可沒有)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.