天天看點

正規表達式文法

了解正規表達式文法:

      正規表達式(regular expression)描述了一種字元串比對的模式,可以用來檢查一個串是否含有某種子串、将比對的子串做替換或者從某個串中取出符合某個條件的子串等。

      \列出目錄時,dir *.txt 或 ls *.txt 中的 *.txt 就不是一個正規表達式,因為這裡 * 與正則式的 * 的含義是不同的。

     \構造正規表達式的方法和建立數學表達式的方法一樣。也就是用多種元字元與運算符可以将小的表達式結合在一起來建立更大的表達式。正規表達式的元件可以是單個的字元、字元集合、字元範圍、字元間的選擇或者所有這些元件的任意組合。

       正規表達式是由普通字元(例如字元 a 到 z)以及特殊字元(稱為"元字元")組成的文字模式。模式描述在搜尋文本時要比對的一個或多個字元串。正規表達式作為一個模闆,将某個字元模式與所搜尋的字元串進行比對。

 普通字元

普通字元包括沒有顯式指定為元字元的所有可列印和不可列印字元。這包括所有大寫和小寫字母、所有數字、所有标點符号和一些其他符号。

元字元彙總

. 比對除換行符以外的任意單個字元。在awk中,句點也能比對換行符。

* 比對任意一個(包括零個)在它面前的字元,(包括由正規表達式指定的字元)

[...]比對方括号中的字元類的任意一個。如果方括号中第一個字元為脫節字元(^),則表示否定比對,即比對除了換行符和類中列出的那些字元以外的所有字元,在awk中也比對換行符。連字元(-)用于表示字元的範圍。如果類中的第一個字元為右方括号(]),則表示它是類的成員。所有其他的元字元在被指定為類中的成員時都會失去他們原來的意義。

^ 如果作為正規表達式中的第一個字元,則表示比對行的開始。在awk中比對字元串的開始,即使字元串包含嵌入的換行符。

$ 如果作為正規表達式中的最後一個字元,則表示比對行的結束。在awk中比對字元串的結尾,即使字元串包含嵌入的換行符。

\{n,m\}比對它前面某個範圍内單個字元出現的次數(包括由正規表達式指定的字元),\{n\}将比對n次出現,\{n,\}至少比對n次出現,而且\{n,m\}比對n和m之間的任意次出現。

\ 轉義随後的特殊字元

擴充的元字元(egrep和awk)

+比對前面的正規表達式的一次或者多次出現。

?比對前面的正規表達式的零次或者一次出現。

|指定可以比對其前面的或者後面的的正規表達式。

()對正規表達式分組。

{n,m}比對它前面某個範圍内單個字元出現的次數,(包括由正規表達式指定的字元),{n}表示比對n次出現,{n, }至少比對n次出現,{n,m}比對n和m之間的任意次出現。(用于POSIX的egrep和POSIX的awk,而不是傳統的egrep和awk)。

普通存在的反斜杠 \

元字元反斜杠(\)将元字元轉換為普通字元(和将普通字元轉換為元字元),它強制将任意元字元解釋為普通文字,以便比對該字元本身。

它的用法:\( \) \{ \} \n

字元類中的特殊字元

\ 轉義任意特殊字元(隻用于awk中) 隻在awk中式特殊的,是以可以使用字元類"[a\]1]"以比對一個a、一個],或一個1。

-當它不在第一個或者最後一個位置時,表示一個範圍

^僅當在第一個位置時表示翻轉比對

字元的範圍

連字元用于指定一個字元範圍,例如,所有大寫字母的範圍可以指定為:[A-Z]

一個數字的數字範圍可以指定為:[0-9]

該字元類有助于解決比對文章引用的問題。

例如:[cC]hapter  [1-9]

它比對字元串‘chapter’或者‘Chapter’且後面跟有空格,然後是從1到9的任意單個數字。

eg: you will find the information in chapter 9.

[0-9a-z?,.;:'"]這個表達式将比對任意的單個字元,可以是數字,小寫字母,問号,逗号,句點,分号,冒号,單引号,引号。記住每個字元類都比對單個字元。

如果指定多個類,可以描述多個連續的字元。

[a-zA-Z][.?!]這個表達式比對“任意後面跟有句點,問号,感歎号的小寫或者大寫的字面”

[-+*/]如果連字元在一個類中是第一個或者最後一個字元,則失去其特殊含義,為了比對算是操作符,在下面的示例中将連字元(-)放在第一位。

用正在比對日期的兩種格式:

MM-DD-YY

MM/DD/YY

排除字元集

通常字元類包括在哪個位置想要比對的所有字元。在類中作為第一個字元的脫位元組(^)将類中的所有字元由排除再被比對之外。相反,除換行符以外的的沒有列在方括号中的任意字元都将比對。

[^0-9] 将比對任意非數字字元。它将比對所有的大寫和小寫字母,以及所有特殊符号,例如,标點符号。

[^aeiou]排除元音,比對任意的輔音,大寫的任意元音,任意标點符号或者特殊字元。

舉例如下的表達式:

\.DS "[^1]" 該表達式比對字元串,“.DS”其後依次跟随一個空格、一個雙引号、一個非數字和一個雙引号。這樣設定是為了避免比對如下:.DS "1"  ,而比對這樣的行: .DS "|"   .DS "2" 

POSIX字元類

類                  比對字元

[:alnum:]       可列印的字元(包括空白字元)

[:alpha:]        字母字元

[:blank:]        空格和制表符

[:cntrl:]         控制字元

[:digit:]         數字字元

[:graph:]       可列印的和可見的(非空格)字元

[:lower:]       小寫字元

[:print:]        可列印的字元(包括空白字元)

[:punct:]      标點符号字元

[:space:]      空白字元

[:upper:]     大寫字元

[:xdigit:]     十六進制數字

重複出現的字元

星号(*)元字元表示它前面的正規表達式可以出現零次或多次。也就是說,如果它修改了單個字元,那麼該字元可以在那裡也可以不在那裡,并且如果它在那裡,那可能會不止出現一個。可以使用星号元字元比對出現在引号中的單詞。

當星号用于修複字元類時,則可以比對類中的任意數目的的字元。

cat summ.txt 

i can do it

i cannot do it

i can not do it

i can't do it

i cant do it

##############################

比對以上語句的否定語句,但是不比對肯定語句,可以使用如下的正則

grep  "can[ no' ]*t"  summ.txt

元字元加号可以被認為是“至少一個”的前導字元,事實上,他和許多人使用的“*”号相對應。

問号(?)比對零次或者一次出現。例如:

“80286”“80386”“80486”“80586”使用正規表達式比對,如果我們還想比對字元串“8086”,可以使用egrep或awk編寫正規表達式。

80[2345]?86  :它比對"80"後面跟的"一個2","一個3","一個4","一個5",或者沒有字元,然後跟字元串“86”。

比對單詞,有時候比對單詞很難,例如:想比對模式“book”,搜尋會命中包含單詞“book”“books”“bookish”"handbook"“booky”,如果遇到此類情況,則需要在"book"前後使用空格來限制比對情況。

舉例:

[root@localhost opt]# cat zhang.txt 

Here are the books that you requested

Yes,it is a good book for children

it is amazing to think that it was called a "harmful book" when once you get to the end of the book,you can't believe

 book.(.為空格的意思)

[root@localhost opt]# grep ' book ' zhang.txt 

但是此表達式隻比對單詞“book”,它會丢掉比對“books”,為了比對單數或者複數單詞,可能要使用星号元字元。 

[root@localhost opt]# grep ' books* ' zhang.txt

. books.*這樣可以比對“book”或者“books”然而,如果單詞後面有逗号,句點,問号或者引号時就不比對“book”。

[root@localhost opt]# grep ' book.* ' zhang.txt

當星号和通配符(.)結合起來使用時,可以比對任意字元的零次或者多次出現。

.  book.* .這個表達式比對字元串“book”,其後面跟有任意個字元或者沒有字元,最後跟着空格。

.  book.? .

定位元字元

有兩個元字元用于指定字元串出現在行首或者行末的上下文。脫字元(^)元字元是訓示開始的單字元正規表達式,美元符号($)元字元是訓示行結尾的單字元正規表達式。這些通常被稱為“定位符”,因為他們将比對限定在特定的位置。

可以使用以下的表達式列印以制表符開始的行:

^.

eg:

[root@localhost opt]# grep -c '^.' zhang.txt 

3

通常,使用vi輸入要由troff處理的文本,并且不想讓空格出現在行的結尾。如果想找到(并且删除他們),下面的正規表達式可以比對在結尾處有一個或者多個的行。

()()*$[()表示的是空格]

[root@localhost opt]# grep -c '  *$' zhang.txt 

比對行首有一個句點,随後跟有兩個字元的字元串,然後是一個空格的行。 ^\...()[()表示的是空格]

可以使用兩個連續的定位元字元來比對空行,例如:

[root@localhost opt]# grep -c '^$' zhang.txt 

2

可以使用sed來删除空行,下面的正規表達式可用于比對空行,即使其中包含空格:'^ *$'。 同樣可使用此表達式比對整個行: '^.*$'

[root@localhost opt]# grep -c '^ *$' zhang.txt 

[root@localhost opt]# grep -c '^.*$' zhang.txt 

5

字元的跨度

這個元字元訓示了一個不确定的長度,這允許你指定重複出現的字元,現在我們來看一對用于指定跨度并決定跨度長度的元字元,可以指定一個字母字元或正規表達式出現的最小或者最大的次數。

在grep和sed中使用\{和\},POSIX egrep和 POSIX awk 使用{和}。在任意情況下大括号包圍一個或者兩個參數。

\{n,m\} :n和m是0到255之間的整數,如果隻指定\{n\}本身,那麼将精确比對前面的字元或者或正規表達式的n次出現。如果指定\{n,m\},那麼就比對出現的次數為n和m之間的任意數。

注意:“?”等價于"\{0,1\}","*"等價于"\{0,\}" , "+"等價于"\{1,\}",沒有等價于"\{1\}"的修飾符。

例如:下面的表達式将比對“1001”、“10001”、“100001”但是不比對“101”或者“1000001”

10\{2,4\}1

[0-9]\{3\}-[0-9]\{2\}-[0-9]\{4\} 3個數字,一個連字元,加兩個數字一個連字元,四個數字

[0-9]\{3\}-[0-9]\{4\}三個數字,一個連字元,四個數字

如果使用POSIX之前的awk,大括号就不用寫,隻能簡單的重複适當次數的字元類。

[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]

選擇性操作

豎線(|)元字元是元字元擴充集的一部分,用于指定正規表達式的聯合,如果某行比對其中的一個正規表達式,那麼它就比對該模式。

例如:LINUX|UNIX将比對包含字元串“Linux”或者“Unix”的行。也可以指定更多的選擇,

LINUX|UNIX|EATANB 表示:使用egrep列印比對這3種模式的任意一種的行。

sed中沒有聯合元字元,可以分别指定每種模式。

分組操作

園括号()用于對正規表達式進行分組并設定優先級,他們是元字元擴充集的一部分,假設在文本檔案中将公司的名稱為:“BigOne”或者是“BigOne Computer”,使用如下的正規表達式:

BigOne ( Computer)?  #将比對字元串"BigOne"本身或者後面跟有一個字元串“ Computer”的形式。同樣,有些術語有時會有全拼,有時會用縮寫,則可以使用如下:

[root@localhost opt]# egrep "Labo(ratorie)?s" mail.list 

Bell Laboratories,Lucent Technologies

Bell Labos

可以使用豎線和圓括号來對選擇性操作進行分組,可以用來指定單複數的比對例如:

compan(y|ies)

注意:在大多數的sed和grep版本中,不能對加圓括号的一組字元應用數量詞。但是在awk和egrep的所有版本中,都是可以的。

測試:使用前文讨論過的新的元字元來重新建構搜尋單個單詞的正規表達式。>想列印,<表示不想列印

[root@localhost opt]# cat book.list 

>This file tests for book in various places, such as 

>book at the  beginning of a line or

>at the end of a line book,

>as well as the plural books and

<handbooks.Here are some

<phrases that use the word in different ways:

>"book of the year award"

>to look for a line with the word "book"

>A GREAT book!

>A great book? No.

>told them about (the books) until it

>Here are thr books that you requested

>Yes,it is a good book for children

>amazing that it was called a "harmful book" when

>once you get to the end of the book, you can't believe

<A well-written regular expression should

<avoid mathing unrelated words,

<such as booky(is that a word?)

<and bookish and

<bookworm and so on.

################################################

[root@localhost opt]# grep ' book.* ' book.list 

它隻是列印我們想要比對行的13行中的8行,并列印我們不想比對行中的2行,這個表達式比對包含單詞“booky”和“bookish”的行,他忽略了行開始或者結束出的“book”,當涉及某種标點符号時它忽略“book”。

為了進一步限制搜尋,我們必須使用字元類,一般地,可以結束單詞的字元清單是标點符号。例如;

? . , ! ; : '

另外,引号,圓括号,大括号和方括号可以包圍一個單詞出現在單詞的左側或者右側:

" () {} []

你還必須調整單詞的複數或者是所有格形式。

是以,應該有兩個不同的字元類,單詞之前和單詞之後。記住我們必須做的就是列出方括号中的類的成員,在單詞前面使用:

["[{(]

在單詞後面使用:

[]})"?!.,;:' s ]

注意:在類中第一個位置放置閉方括号,表示它是類的成員而不是閉方括号。将以上的類放置在一起,得到如下的正規表達式:

["[{(]*book[]})"?!.,;:' s]*

[root@localhost opt]# grep " [\"[{(]*book[]})\"?\!\.\,;\:' s]* " book.list 

我們排除了我們不想要的行,但是都是由在行的開始或結尾處出現的字元串所導緻的錯誤。因為在行的開始處或者結尾處沒有空格。是以模式不被比對,可以使用定位元字元^和$。因為要比對一個空格或行的開始或者結尾,可以使用egrep并指定的“或”元字元,同時用圓括号分隔。例如:為了比對行的開始或者一個空格,可以編寫下面的表達式:

(^| )因為|和()是元字元擴充集的一部分,是以如果使用的是sed,則必須編寫不同的表達式來處理每一種情況。

是以表達式如下:

[root@localhost opt]# egrep "(^|)[\"[{(]*book[]})\"?\!\.\,;\:' s]*( |$)" book.list 

比對的範圍

A*Z這個表達式比對“零次或者多次出現的A,同時A後面跟字元串Z”。它産生的結果與僅僅指“Z”是相同的。字元A可以在那裡也可以不在那裡,事實上,字元Z是唯一比對的字元。

例如:

[root@localhost opt]# grep 'A*Z' hello 

All of us,including Zippy,our dog

some of us ,including Zippy,our dog

如果我們想要比對的範圍擴充到從A到Z,則需要修改正規表達式為:A.*Z

" .* "可以解釋為出現零次或者多次的任意字元,這意味着可以找到“出現任意次的字元”,包括什麼也沒有的情況。整個表達式表示A和Z之間有任意數目的字元,“A”是模式中的開始字元,“Z”是最後一個字元,在它們之間可以有任意個字元或者是沒有字元。

[root@localhost opt]# grep 'A.*Z' hello 紅色字型表示比對的範圍

All of us,including Zippy,our dog

比對的範圍從A到Z,相同的正規表達式還比對下面的行

[root@localhost opt]# grep 'A.*Z' hello 

i heard it on radio station WVAZ ^^ 1060

字元串A.*Z比對A後面跟有任意個字元(包括零個字元),再跟有Z的模式:

All of us, including Zippy and Ziggy

All of us, including Zippy and Ziggy and Zelda

注意:正規表達式A.*Z在每種情況下都比對可能為最長的範圍。當我們想要比對最短的範圍時會出問題。

限制範圍

前面說過,正規表達式嘗試比對最長的字元串,并且這可能會引起意想不到的問題。例如:以下的表達式

" .* "

輸入字元串如下:

[root@localhost opt]# cat list1.txt 

.Se "Appendix" "Full Program Listings"

要比對第一個參數,則正規表達式如下:

  \.Se ".*"

然而,因為模式中的第二個引号與該行上的最後一個引号比對,是以它結束比對整個行。如果知道參數的個數,那麼可以對每個進行說明:

 \.Se  ".*" ".*"

雖然這種方法可以像期望的那樣工作,但是每行也許不會有相同書目的參數,省略你隻想要第一個參數。這裡有一個比對兩個引号之間最短範圍的正規表達式:

  "[^ "]*"

現在我們來看看兩列數字之間使用句點字元(.)作為引導符的幾行:

1........5

5.........10

10........20

100.........200

這裡比對引導字元的困難是它們的數量是可變的,假如想用單個制表符取代所有的引導符,則可以按下面的形式編寫一個比對行的正規表達式:[0-9][0-9]*\.\.*[0-9][0-9]*

為了限制比對,可以指定所有的行共用句點的最小數目:[0-9][0-9]*\.\{5,\}*[0-9][0-9]*這個表達式使用sed中可用的大括号來比對“一個數字後面至少跟5個句點,然後再跟有一個數字的情況”。

[root@localhost opt]# sed 's/\([0-9][0-9]*\)\.\{5,\}\([0-9][0-9]*\)/\1-\2/' list2.txt 

1-5

5-10

10-20

100-200

使用喜歡的元字元

有用的正規表達式:                                                         

州的郵政編碼                                      

(空格)[A-Z][A-Z](空格)

城市、州                                             

^ .*,(空格)[A-Z][A-Z]

城市、州、郵編(POSIX/egrep)             

^ .*,(空格)[A-Z][A-Z][0-9]{5}(-[0-9]{4})?

月、日、年                                           

[A-Z][a-z]\{3,9\}(空格)[0-9]\{1,2\},(空格)[0-9]\{4\}

美國社會保險号                                     

[0-9]\{3\}-[0-9]\{2\}-[0-9]\{4\}

北美地區電話                                        

[0-9]\{3\}-[0-9]\{4\}

格式化的美元數額                                  

\$[(空格)0-9]*\.[0-9][0-9]

troff嵌入的字型請求                             

\\f[(BIRP]C*[BW]*

troff的請求                                            

^  \.[a-z]\{2\}

troff 宏                                                   

^  \.[a-z12].

帶有參數的troff的宏                               

^  \.[a-z12].(空格)" .*"

HTML嵌入的代碼                                    

<[^ >]*>

Ventura Publisher style codes            

^ @.*(空格)=(空格).*

比對空行                                               

^$

比對整行                                                

^.*$

比對一個或者多個空格                             

(空格)(空格)*

本文轉自 妙曼  51CTO部落格,原文連結:http://blog.51cto.com/yanruohan/1900323,如需轉載請自行聯系原作者

繼續閱讀