C 正規表示式精義 1

2021-05-01 11:39:21 字數 3969 閱讀 1529

主要在於兩方面:1. 接受正規表示式的思維方式; 2. 熟悉表示式裡面各種各樣的符號的用法.第一點的難度在於這是個新東西, 和以前的知識結構不一樣; 第二點的難度在於各種各樣的環境下都對最基本的正規表示式做了很多擴充套件, 引入了各種各樣的新的符號, 這樣, 就使得學的時候一下子面對太多的複雜度不知所措. 舉例來說, 大多數教程把 ^$*+-(){}|.?/ 這些符號全部放到一起講, 全然不分他們的層次關係, 導致學習者雲裡霧裡. 同時, 不同的工具又定義了自己的特殊規則, 使得學習曲線更加陡峭. 因此, 我打算把正規表示式的知識點, 分幾個不同的層次, 一一剖析. 在這一部分中, 我把正規表示式瑣碎的細節一一剔除, 希望看到這篇文章的, 願意學習正規表示式的讀者, 能夠迅速從這些繁瑣的細節中解脫出來, 掌握其本質.

首先說正規表示式是什麼. 正規表示式是一種描述性的語言, 用來概括一類字串 (或者說乙個字串集合).我們當然可以用自然語言來描述一類字串, 比如我們說, 以 「010 開頭的**號碼」, 「夾在html 的中間的內容」, 「含有 hello 的字串」, 「負數」, 「ip位址」 「郵箱位址」, 等等. 其實在實際應用中, 我們也常常有這個需求, 比如說提取一篇郵件中所有的 email 位址 (查詢), 或者把提取某類**號碼, 公升個位, 加個區號什麼的 (替換). 人當然可以做這個事情, 但是這個事情重複且單調, 又並不需要太多的智力, 因此, 計算機是最好的工具. 但是問題是, 我們怎麼能夠告訴計算機, 我們對哪類字串感興趣呢? 計算機科學家就幫我們設計了一種讓人能夠簡單的寫出來, 表達我們人類想表達的含義, 而計算機又恰好能夠很容易的理解和處理的一種表示式, 這就是正規表示式了. 從人和計算機的角度說, 正規表示式是一種人和計算機都能輕鬆處理的約定, 用來描述一類具有某個性質的字串.

正規表示式它既有傾向於人的思考方式的一面, 也有傾向於計算機工作原理 (有限自動機) 的一面. 因此, 傳統意義上, 如果想真正理解正規表示式, 就要從理解計算機原理入手. 所幸的是, 我們普通使用者, 在日常使用中, 並不需要了解計算機的原理, 因為這麼多年技術的發展給了正規表示式很多新特性, 讓正規表示式越來越脫離計算機的侷限, 變得更加適合複雜的任務, 但這樣的代價是正規表示式的細節越來越繁雜了, 對於初學者來說更加難學了. 因此我們在這裡, 先講本質, 後談細節.

最基本的正規表示式, 只有三句話:

乙個字串是乙個正規表示式, 比如 aaa, 就是乙個正規表示式, 它描述了乙個字串集合, 這個字串集合裡面只有 aaa 這乙個元素

兩個正規表示式可以直接串起來, 比如 aaabbb 其實, 是由六個正規表示式 a a a b b b 接起來組成的. 我們先籠統的說, 接起來就等於把描述的內容接起來, 等一下再詳細解釋接起來的含義.

兩個字串, 比如 aaa 和 bbb, 用 | 連起來, 變成了 aaa|bbb, 也構成乙個正規表示式, 它描述的字串集合是原來分別的並集, 比如 aaa|bbb 描述了乙個集合, 這個集合裡面有 兩個字串.

好了, 就這兩三話, 就可以解釋正規表示式最基本的思維方式了: 用乙個表示式, 去描述一類字串(或者說, 乙個集合).

光有這兩個, 還不夠強大, 因為上面的正規表示式, 我寫幾個, 就描述了幾個字串, 也就是說, 描述來, 描述去, 都是有限的集合, 不能描述無限的集合. 而我們想要描述的整數啊, 網域名稱啊, 郵箱位址啊, 都是一切就有可能的, 因此, 我們有必要引入乙個新的記號, 能夠描述無限的集合,

乙個正則式 x 可以加上乙個 *, 用來描述任意多個原來 x 描述的字串拼起來的字串.

這句話比較費解, 我們用例子來說明一下, 比如 a* 這個正規表示式, 我們知道 a 描述了一類字元, 這類字元裡面只有乙個 a, 所以, a* 描述了乙個或者多個 a.

我們再看 a | b* , 按照定義, 這個正規表示式描述了 a 和 b, bb, bbb 等. 如果我們引入乙個括號, 寫成 (a|b)* , 那麼 a|b 就變成乙個整體, 描述了 a 或者 b, 這時候, (a|b)* 就是一切只由 a, b 組成的字串. 這裡的括號, 是為了避免歧義, 表示 * 是作用在 a|b 整體上的. 這時候, (a|b) 描述了 a 和 b, 整體加了乙個 *, 意味者我們可以任意選 a 或者 b 乙個接乙個拼起來, 所以, aba, aab 都是在 (a|b)* 的那一類裡面的. 注意, * 可以匹配 0 個, 就是說, 這裡面包含了什麼都沒有. 比如說 ab*c 也描述了 ac, 因為中間可以有 0 個 b. 如果您想至少要乙個b, 可以寫成 abb*c.

為了幫助您理解接起來, 我們再看乙個複雜的例子, o(n|ff). 我們知道, n|ff 描述了 n 或者 ff. 當我們直接把 o 接在前面的時候, 描述的是 on 或者 off. 就是說, 接起來的時候, 要把 o 和後面每種情況都組合一次. 我們再看 (a|o)(n|ff). 前面描述的是 a 或者 o, 後面描述的是 n 或者 ff, 接起來, 描述了 an, aff, on, off.

我們都知道, 正規表示式描述的是一類字串, 所以, x 和 y 在接起來變成 xy 以後, 自然的變成了描述 每一種 x 裡面的字串和 y裡面字串接起來的情況. 同樣, * 好像把 x 和自己接起來多次一樣 (可以是任意次), 每次只要接起來的是x裡面的字串, 就一定被 x* 所表述.

(熟悉集合的朋友立即知道 正規表示式是用乙個表示式代表了乙個集合, x|y 等價於兩個集合的並集, 而 xy 拼起來等價於他們所有的元素 x, y 拼起來的集合).

好了, 恭喜您, 您已經學會正規表示式了. 真的, 你已經全部學會了正規表示式的知識. 不過不著急, 我們先回顧一下正規表示式的要點:

1. 正規表示式由普通的字元, 以及幾個特殊的字元, 即 括號 (), 或者 | 和 星號 * 組成. 用來描述一類字元.

2. | 表示或者. 如果有兩個正規表示式 x 和 y, 那麼 x|y 就描述了原來 x 描述的和 y 描述的.

3. 正規表示式可以接起來, 變成乙個更長的, 描述了乙個各個部分被那些被接起來的正規表示式描述的字串.

4. () 是為了避免歧義.

我們上面說的這四個, 就是 100% 如假包換的正規表示式了. 以後的, 都是為了更加方便的使用正規表示式, 而又引入的一些擴充套件. 恰恰是這些擴充套件, 讓初學者陷入了細節的泥潭. 我們在下一節, 乙個乙個的來對付諸如 +, [, -, ], ^, $, , 等這些非基本的高階的功能. 需要強調的是, 這些高階的功能, 其實都只是為了人書寫方便, 而且是完全可以用我們這裡說的最基本的幾個規則代替的. 這些高階功能, 我們下節再講.

練習:寫出匹配以下性質字串的正規表示式:

1. 字串 2009

2. 周曙光同學有兩個名字, 分別叫做 zola 和 zuola, 人們常常混淆. 請幫周曙光同學設計乙個正規表示式, 可以幫他匹配自己的名字.

3. 二進位制數字 (最少有一位, 但只含有 0 或者 1的)

4. 非零的十進位制數字 (有至少一位數字, 但是不能以0開頭)

練習軟體:

有一些比較好的軟體幫你學習正規表示式, 我推薦初學者用 egrep. 可以在 windows 下用, 具體用法是在命令列 打入 egrep 「正規表示式」 檔名

egrep 會把檔案裡面和正規表示式匹配的行 (該行含有乙個字串, 被正規表示式描述了) 打出來. egrep -o 「正規表示式」 檔名 的話就會只打出那個完全匹配的字串, 而不是行. 另外, 在 linux 下可以用 grep –color 「表示式」 檔名, 這樣, 匹配上的那個字串, 會被高亮顯示出來.

練習檔案:

0108200920088964

zuola -d

zooooola

world hello -012012 2009

0909 zola zhou

0101001

zuola

做實驗)

答案:1. 2009

2. z(|u)ola [或者您可以寫成 zuola|zola]

3. (0|1)(0|1)*

4. (1|2|3|4|5|6|7|8|9)(0|1|2|3|4|5|6|7|8|9)*

你會看到第四題的答案很笨拙, 居然寫了這麼長. 後面的大部分細節, 就是為了諸如此類的寫得更加簡潔一點.

正規表示式 1 初識正規表示式

簡單地說,正規表示式就是一套處理字串的規則和方法,以行為單位對字串進行處理,通過特殊的符號的輔助,我們可以快速的過濾,替換某些特定的字串。運維工作中,會有大量訪問日誌,錯誤日誌,大資料。如何能夠快速的過濾出我們需要的內容,這就需要正規表示式。awk,sed,grep egrep 三劍客要想能工作的更...

正規表示式 1 正規表示式基礎

1.正規表示式基礎 正規表示式描述了一種字串匹配的模式,即可以使使用者通過一系列普通字元或特殊字元構建能夠明確描述文字字串的匹配模式,可以用來檢查某個字串是否含有某種子字串,將匹配的子字串做替換或者從某個字串中取出符合某個條件的子字串等。1.1 正規表示式的基本結構 乙個正規表示式就是由普通字元 如...

正規表示式(1)

正規表示式 正則 表示式提供了一種標準的 實用的方式,來分析文字檔案 搜尋並有選擇性地替換出現的紫字串或者文字模式。如果對正規表示式不熟悉的話,可以把它看作ms dos裡的萬用字元,用來指定一組檔案 比如 txt 或者看作sql查詢語句中配合like命令使用的特殊字元 select name,cit...