歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> SHELL編程 >> Linux.Shell編程筆記-正則表達式

Linux.Shell編程筆記-正則表達式

日期:2017/3/1 13:36:55   编辑:SHELL編程

第四章 正則表達式

什麼是正則表達式

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

正則表達式的廣泛應用

正則表達式在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:]]* 數字(可沒有)

Copyright © Linux教程網 All Rights Reserved