正則表達式簡明教程

前言

這是一份比較簡單的正則表達式指南,是我按照自己學習正則時做的筆記整理出來的,並不能保證沒有瑕疵,但我會盡最大可能來完善它,特此我在標題上加上了 持續更新

格式

爲了使大家更加容易閱讀,我在使用了幾處高亮, 例子統一用黃色標註, 注意事項使用紅色警示, 專業術語加粗。

目錄

  1. 引言
  2. 什麼事正則表達式
  3. 元字符
  4. 重複
  5. 轉義字符
  6. 反義
  7. 字符類
  8. 分支條件
  9. 分組
  10. 向後引用
  11. 零寬斷言
  12. 負向零寬斷言
  13. 註釋
  14. 貪婪與懶惰
  15. 附錄

引言

最近給大一講解了下正則表達式,順便整理了份資料,共享出來。可能有點小偏差,但是正如題目中所說的,這是一篇不斷完善,不斷擴充的博文。 好了,言歸正傳,我們平時會遇到比較多的字符串,尤其是在處理文本的時候,我想這方面做Linux運維的應該深有體會。如果我們需要搜索某個文本中 具有某種規律的字符串時應該怎麼辦呢?很明顯grep+正則。下面我就來簡單介紹下什麼是正則表達式,以及它的用法。

什麼是正則表達式?

在計算機科學中,是指一個用來描述或者匹配一系列符合某個句法規則的字符串的單個字符串。如,我們可以使用 25[0-5]|2[0-4]\d|^1?[1-9]?\d$來匹配0-255。

元字符

\b 匹配字符串的開始或結束(隔離空格)
\w 匹配字母、數字、下劃線或漢字
\s 匹配任意的空白符
^ 匹配字符串的開始
$ 匹配字符串的結束
. 匹配除換行符以外的任意字符
\0nn 匹配ASCII中八進制代碼爲nn的字符
\xnn 匹配ASCII中十六進制代碼爲nn的字符
\unnnn 匹配Unicode中十六進制代碼爲nn的字符
\cN 匹配ASCII控制符
這些都是十分基礎的元字符,下面我們給出2個例子:
  1. ^\d\s\d$ 這條正則表達式表示一個字符串,它的特徵是以數字開始和結束,並且兩個數字之間有個空格
  2. \btt\b 這條正則表達式能夠識別“cattac tt”中的後一個“tt

重複

* 重複零次或更多次
+ 重複一次或多次
? 重複零次或一次
{n} 重複n次
{n,} 重複n次或更多
{n,m} 重複n到m次
重複如果使用得當,能夠極大地縮短正則表達式地長度,以下是2個簡單的例子:
  1. Linux\d+ 這條表達式能夠匹配Linux以及其後更隨的至少一個數字,有點拗口,打個比方,Linux3
  2. \b\d{7}\b 這條表達式將能夠匹配獨立的7個數字組成的字符串

轉義字符

從上面的元字符中我們可以看到有些字符被正則表達式給佔用了,此時我們就需要將他們轉義,十分簡單,我們只需要在被佔用的字符前面加上\,對就像大多數程序語言一樣處理就行了,如\.,\^,\$,\\,\(,\)等等。
\a 報警
\t 製表符
\v 豎向製表符
\f 換頁符
\n 換行符
\e Esc

反義

\W 匹配任意不是\w的字符
\S 匹配任意不是\s的字符
\D 匹配任意不是\d的字符
\B 匹配任意不是\b的位置
[^x] 匹配除了x以外的任意字符
[^as] 匹配除了as以外的任意字符
反義就相當於元字符的補集,其中的\B比較難以理解。 那麼,我們來深究下\b到底表示的是什麼東西?它表示一個特殊位置,即字符與空格之間的位置。 由此類比,\B表示的是字符與字符之間的位置,不過這裏的字符並不包括空白字符。 \B並不常用,它包含的位置實在是太具普遍性了。。。 同樣,我們給出2個例子:
  1. \b[^z]+\b 匹配不含z的字符串
  2. <s[^>\s]+> 匹配用<>括起來的以s開頭的不包含空格的字符串

字符類

上述的\d表示數字0-9,那麼假設我們只需要匹配2-5,那麼該怎麼辦?顯然,到目前爲止,我們並沒有提到相關技術。 此時我們需要的是自己定義字符類了,方法很簡單,使用[]將你需要定義的字符類括起來就行了,以下是幾個例子:
  1. [2-5] 表示匹配2-5,當然你完全可以使用[2345],如果你不嫌累的話
  2. [a-z] 匹配所有小寫字母
  3. [a-zA-Z] 匹配所有大小寫字母

分支條件

什麼是分支條件呢?請不要着急,我們先來講述一個案例。 假設現在我們有2串電話號碼,分別是(010)12345678和010-12345678,它們均是某電話號碼的合法表示,那麼我們應該如何來通過正則表達式來匹配呢? 很簡單,使用分支——“|”,也可以理解爲“或”。接下來我們就試着用分支來解決上述問題。
  1. \(010\)\d{8}匹配(010)那種表示方式
  2. 010-\d{8}匹配另外一種
  3. 我們將上述兩個式子通過|連接,即(\(010\)|010-)\d{8}

分組

細心的讀者應該會發現,到目前爲止我們所針對都是單個字符的匹配,那麼一段字符串如何精確匹配? 這個時候我們就要引入“分組”的概念了。所謂分組,其實就是使用()將需要匹配的字符串括起來,這個時候的重複就是針對整個括號內的內容了。同時,分組也爲我們引入新的概念奠定了基礎,這個後面會提到。 用例子來說話:
  1. ([a-z]\d)+ 匹配一個或者多個以小寫字母和數字的組合
  2. (\d{3}.){3}\d{3} 實現一字符串,其具體形式類似於ip,只是其有效值爲000-999,我們暫時不考慮複雜的例子

向後引用

其實分組還有個特性,那就是它的識別字符會被引擎直接標號,供我們接下來直接引用,下面我們就來介紹這方面的特性。 首先是格式,這裏的具體格式有兩種,其一是使用默認組號;其二是自定義標記。下面我們分開來介紹。 默認形式\b(\w+)\b\s+\b\1\b 我將相關部分使用紅色標識了,這裏的第一個分組內容被引擎匹配後,會被編上號碼(注意,是從1開始的),接下來我們就可以通過\1來引用了 用戶定義 \b(?<Word>\w+)\b\s+\b\k<Word>\b 這個表達式的功能和上面是一樣的只是我們此時將默認標識換成了自己定義的標誌,不過這裏其實還有另一種形式 \b(?'Word'\w+)\b\s+\b\k'Word'\b 

零寬斷言

零寬斷言,聽起來很玄乎,其實它和之前介紹的^,$,\b一樣,都是用來標識一個位置,只不過我們可以自由定義這個位置罷了。 (?=exp)也叫 零寬度正預測先行斷言,它斷言自身出現的位置的後面能匹配表達式 exp。比如 \b\w+(?=ing\b),匹配以ing結尾的單詞的前面部分(除了ing以外的部分),如查找I'm singing while you're dancing.時,它會匹配sing和danc。 (?<=exp)也叫 零寬度正回顧後發斷言,它斷言自身出現的位置的前面能匹配表達式 exp。比如 (?<=\bre)\w+\b會匹配以re開頭的單詞的後半部分(除了re以外的部分),例如在查找reading a book時,它匹配ading。 下面這個例子同時使用了這兩種斷言:
  • (?<=\s)\d+(?=\s)匹配以空白符間隔的數字(不包括這些空白符)。

負向零寬斷言

零寬斷言是定義符合條件的位置,那麼必然,它是有補集的,那就是負向零寬斷言。多位負向零寬斷言,就是指不符合定義的位置。 (?!exp)也叫 零寬度負預測先行斷言,斷言此位置的後面不能匹配表達式 exp。例如: \d{3}(?!\d)匹配三位數字,而且這三位數字的後面不能是數字; \b((?!abc)\w)+\b匹配不包含連續字符串abc的單詞。 (?<!exp)也叫 零寬度負回顧後發斷言,斷言此位置的前面不能匹配表達式 exp。例如: (?<![a-z])\d{7}匹配前面不是小寫字母的七位數字。

註釋

就像程序語言能夠添加註釋一樣,正則表達式也是可以的,尤其是在式子比較長的時候,註釋顯得尤爲重要。使用註釋的方式就是(?#comment),例如 2[0-4]\d(?#200-249)|25[0-5](?#250-255)|[01]?\d\d?(?#0-199)

貪婪與懶惰

正則表達式是具有雙重人格的,爲什麼這麼說呢?且看本段。 當正則表達式中包含能接受重複的限定符時,通常的行爲是匹配儘可能多的字符。例如: a.*b,它將會匹配最長的以a開始,以b結束的字符串。如果用它來搜索aabab的話,它會匹配整個字符串aabab。這就是 貪婪匹配。 有時,我們更需要 懶惰匹配——匹配儘可能少的字符。前面給出的限定符都可以被轉化爲懶惰匹配模式,只要在它後面加上一個問號?。這樣.*?就意味着匹配任意數量的重複,但是在能使整個匹配成功的前提下使用最少的重複。例如: a.*?b匹配最短的,以a開始,以b結束的字符串。如果把它應用於aabab的話,它會匹配aabab
*? 重複任意次,但儘可能少重複
+? 重複1次或更多,但儘可能少重複
?? 重複0次或1次,但儘可能少重複
{n,m}? 重複n到m次,但儘可能少重複
{n,}? 重複n次以上,但儘可能少重複

附錄

修改記錄:

2013-3-8 --> 編寫正則表達式最基礎的知識點
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章