歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux綜合 >> Linux資訊 >> 更多Linux

磨練構建正則表達式模式的技能

    通過本文的學習,您可以增加一些有用的設計實際正則表達式 (regeXP) 的技能。構建正則表達式是任何管理員日常工作中的一部分。為了構造返回所需條件的成功正則表達式,需要學習以模式匹配的角度進行思考,而這種技能需要花大量的時間進行練習。

引言

    UNIX® 管理員每天都需要構建和使用正則表達式 (regexp) 進行文本模式匹配。大多數語言都支持正則表達式的某種實現。有的應用程序(如 EMACS)具有正則表達式搜索功能,並且您可以通過各種命令行工具使用正則表達式。無論什麼應用程序,構建正確的正則表達式的關鍵之處在於,識別僅滿足需要匹配的數據的模式,以便在輸入中排除其他不必要的內容。

出於這個目的,本文將逐步介紹幾種正則表達式模式構建技巧,並介紹它們如何幫助您完成各種常規任務。

使用正則表達式 (regexp)

     除非特別說明,否則本文中使用的示例都是擴展可移植操作系統接口(擴展 POSIX)的正則表達式。如果通過命令行(如使用 egrep 實用工具)使用它們,您應該根據需要引用各種正則表達式。請記住,不同的正則表達式實現之間存在一些區別,您可能不得不適應所使用的特定的工具、應用程序或語言中的具體實現。

匹配整行內容

     ^ 元字符匹配行首,而 $ 匹配行尾,如果將它們組合在一起(如 ^$),它們將匹配空行。(這個表達式的鏡像,即 $^,是不可能匹配成功的,它將永遠 都無法匹配到有效行。)這個基本的正則表達式是許多復雜正則表達式的基礎,如果您還不習慣使用這個基本的正則表達式,那麼您應該逐步養成使用它的習慣。使用它來構建匹配整行內容 的模式。

    在用戶字典文件 (/usr/dict/Words) 中搜索是一個很好的基本模式。(有些版本的 UNIX 將用戶字典放在 /usr/share/dict/words 中。)

    例如,假設您忘記了如何拼寫單詞 fUChsia。其中是否包含 sh 或 cs 呢?您所知道的只是,它以 fu 開頭並以 ia 結尾。

嘗試使用這個模式進行搜索:

$ egrep -i '^fu.*ia$' /usr/dict/words

-i 標志表示在搜索過程中不區分大小寫。在這個示例中,因為 fuchsia 拼寫正確,所以在返回的單詞中包括這個單詞。

根據長度匹配行

使用大括號元字符 ({ }) 指定前面的正則表達式匹配多少次,如表 1 所示。當您將它們添加到剛才介紹的整行搜索中時,您可以指定行的長度。

表 1. 大括號元字符的含義 示例 描述 {X} 這個字符對前面的正則表達式匹配 X 次。 {X,} 這個字符對前面的正則表達式匹配 X 或更多 次。 {X,Y} 這個字符對前面的正則表達式匹配至少 X 而不超過 Y 次。

並不是所有擴展正則表達式的實現都支持大括號。此外,根據具體的實現,您可能需要先使用反斜槓對其進行轉義。

您可以使用這個正則表達式得到字典中以單詞長度為順序的報告。所獲得結果的數目取決於本地系統的字典文件中單詞的數目,然而,它應該與清單 1 所示類似。在這個示例中,最常見的單詞長度是 9 個字母,該字典中有 32,380 個匹配單詞。該字典中不包括 25 個字母或更長的單詞,並且最長的單詞並不是您認為的 21 個字母長的 disestablishmentarian(有 81 個同樣長度的單詞,包括 superincomprehensible 和 phoneticohieroglyphic),這個 UNIX 字典中最長的單詞有 5 個,包括 pathologicopsychological。

清單 1. 計算字典中 X 個字母的單詞的個數

$ for i in `seq 1 32` > { > echo "There are" `egrep '^.{'$i'}$' /usr/dict/words \ wc -l` "$i-letter words in the dictionary." > } There are 52 1-letter words in the dictionary. There are 155 2-letter words in the dictionary. There are 1351 3-letter words in the dictionary. There are 5110 4-letter words in the dictionary. There are 9987 5-letter words in the dictionary. There are 17477 6-letter words in the dictionary. There are 23734 7-letter words in the dictionary. There are 29926 8-letter words in the dictionary. There are 32380 9-letter words in the dictionary. There are 30867 10-letter words in the dictionary. There are 26011 11-letter words in the dictionary. There are 20460 12-letter words in the dictionary. There are 14938 13-letter words in the dictionary. There are 9762 14-letter words in the dictionary. There are 5924 15-letter words in the dictionary. There are 3377 16-letter words in the dictionary. There are 1813 17-letter words in the dictionary. There are 842 18-letter words in the dictionary. There are 428 19-letter words in the dictionary. There are 198 20-letter words in the dictionary. There are 82 21-letter words in the dictionary. There are 41 22-letter words in the dictionary. There are 17 23-letter words in the dictionary. There are 5 24-letter words in the dictionary. There are 0 25-letter words in the dictionary. There are 0 26-letter words in the dictionary. There are 0 27-letter words in the dictionary. There are 0 28-letter words in the dictionary. There are 0 29-letter words in the dictionary. There are 0 30-letter words in the dictionary. There are 0 31-letter words in the dictionary. There are 0 32-letter words in the dictionary. $

 

 

匹配單詞

圍繞字符 \< 和 \> 是非常有用的模式構造器:它們將要匹配的整個單詞 括起來,這表示,它們不會匹配帶括號的模式,除非該模式本身就是一個單詞。單詞 定義為兩側由非單詞字符描述的、任意數目組成單詞的字符(數字、字母和下劃線字符)。非單詞字符包括下面的所有字符:

行首 空白字符 標點符號 行尾 任何除字母、數字或下劃線以外的字符

這些圍繞字符可以節省大量的時間,但是它們常常沒有被充分地利用,可能是因為並非所有的正則表達式實現都支持它們。如果您的正則表達式實現支持它們,那麼您應該逐步養成使用它們的習慣。

將需要單獨匹配的單詞括起來,如下所示:

\<system\>

這個示例中的正則表達式不會匹配單詞 ecosystem、systemic 或 system/70,也不會匹配模式 system 出現在行中任意位置的那些行,它將僅僅 匹配 system 作為獨立的單詞出現的那些行。

圍繞字符與圓括號中的分組結合在一起,可以用來匹配部分 單詞。

要匹配包含以 pre 開頭 的單詞的那些行,可以使用:

\<\(pre\).*\>

前面的示例將匹配包含單詞 preface 和 preposterous 的行,但不會匹配 spread 或 Dupre。

匹配重復單詞

這裡介紹一種使用單詞圍繞字符匹配重復單詞的快速方法,重復單詞表示一個單詞在空格之後再次出現。您還可以使用逆向引用,這是大多數流行的正則表達式實現中的一種遞歸特性,它可以匹配模式本身的某一部分。(將模式中需要引用的部分使用圓括號括起來,然後使用反斜槓加上需要進行引用的圍繞字符編號來調用逆向引用:1 表示第一個圓括號分組,2 表示第二個圓括號分組,依此類推。)

要查找重復的單詞,搜索在任意數目的空格之後再次出現該單詞的情況,可以通過對第一個使用圓括號的部分進行逆向引用來實現:

(\<.*\>)( )+\1

這個示例匹配縮寫形式和任何類型的單詞,但是它不會匹配由標點符號分隔的重復單詞,如 It's been a long, long time。

要匹配所有的重復單詞,包括由空格和 任意標點符號分隔的重復單詞,可以使用下面的表達式:

(\<.*\>).?( )+\1

如果需要對這些正則表達式使用 grep,則務必使用 -i 標志,以便在搜索中不區分大小寫。

匹配小時

讓我們再來看另外一類常見的問題:時間和日期。這裡介紹了一些設計匹配正確模式的正則表達式所需要考慮的事項。

您無法搜索任何兩位的數字來匹配分鐘和秒,因為它們僅僅是從 0 到 59,要匹配它們,您需要使用方括號將表示十位和個位的范圍括起來:

要匹配標准的 12 或 24 小時格式的小時,可以使用下面的表達式:

(([0-1]?[0-9])([2][0-3])):([0-5][0-9])(:[0-5][0-9])? 要匹配 12 小時 AM/PM 格式、帶或不帶秒數的時間,甚至匹配大寫或小寫、不帶後綴 AM 或 PM 標識符的時間,可以使用下面的表達式:

([^0-9])([0-1]?[0-9]){1}(((:([0-5]){1}([0-9]){1}){1,2})(( )?([AP]M)([ap]m)))?

如果在上一個示例中沒有開始的否定語句,它將匹配不帶冒號的時間,這將取決於輸入數據,可能會匹配中波廣播電台(在美國稱為調幅 AM 電台),如 1450 AM。

匹配月份

匹配 12 個月中的任何月份需要一個使用 操作符進行分隔的列表,但有時會使用不同的方式對日期進行縮寫:

要查找完整拼寫或三字母縮寫的 12 個月份,可以使用下面的表達式(位於一行):

Jan(uary)?Feb(uary)?Mar(ch)?Apr(il)?MayJun(e)?Jul(y)? Aug(ust)?Sep(tember)?Oct(ober)?Nov(ember)?Dec(ember)? 您可以加以想象並搜索完整拼寫或三字母縮寫的變形,即僅當後面緊跟著一個空格或點號的情況,可以使用下面的表達式(位於一行):

Jan(uary \.)Feb(uary \.)Mar(ch \.)Apr(il \.)May( \.)Jun(e \.)Jul(y \.)Aug(ust \.)Sep(tember \.)Oct(ober \.)Nov(ember \.)Dec(ember \.)

請注意,在上面的這兩個示例中,May 是一個特殊的例外。在所有的月份中,它是唯一的完整拼寫與三字母縮寫相同的月份,所以成功的匹配必須包含這兩種變形中的任何一種 作為其縮寫,因此像“Mayflower”這樣的單詞不會導致誤報。

當匹配模式前面的字符不是空格或行首時,這些示例還是會失敗(返回誤報的結果)。這不太可能會出現在英語散文中,但是可能出現在程序源代碼中,因為其中可能使用了像 NumOct 這樣的變量名。

要修復這些問題,可以執行下面的操作:

使用圓括號將整個正則表達式括起來,並在它的前面加上另一個限定符,用於匹配行首或者空格字符,如下所示(位於一行):

(^ )(Jan(uary \.)Feb(uary \.)Mar(ch \.)Apr(il \.) May( \.)Jun(e \.)Jul(y \.)Aug(ust \.)Sep(tember \.)Oct(ober \.)Nov(ember \.)Dec(ember \.)) 另一種完成這個任務的方法是,在該正則表達式的前面加上一個限定符,以匹配非文字數字的字符,如下所示(位於一行):

([^A-Za-z0-9])(Jan(uary \.)Feb(uary \.)Mar(ch \.) Apr(il \.)May( \.)Jun(e \.)Jul(y \.)Aug(ust \.) Sep(tember \.)Oct(ober \.)Nov(ember \.)Dec(ember \.))

但是仍然存在潛在的問題,對於搜索整篇英文散文,這些示例並不可靠,因為它們可能返回錯誤的匹配結果,如“Janelle”或“Augury”這樣的單詞。要修復這個問題,您必須使用單詞圍繞字符將每個月份括起來。

本文開頭提到,正確的正則表達式應該僅返回需要匹配的數據,以便在輸入中排除其他不必要的內容。這種措詞是經過仔細考慮的,因為對於構建正則表達式來說,這與上下文有關。對於有些情況,前面的示例非常適合,無需添加額外的單詞圍繞字符。在其他的情況下,可以對其進行相當程度的簡化,例如,如果您正在搜索僅包含大寫的日期數值數據的日志文件,那麼只需要使用像 [A-S] 這樣的正則表達式來匹配包含月份名稱的行。

匹配日期

您可以結合一些表 1 所示的數量匹配來匹配日期。

要匹配“month, day, years”,可以使用下面的正則表達式(因為撇號字符是該正則表達式的一部分,所以必須使用雙引號將它括起來,如下所示):

"[A-Za-z]{3,10}\.? [0-9]{1,2}, ([0-9]{4}'?[0-9]{2})"

這個正則表達式匹配 9 種不同的日期格式:

MONTH [D]D, YY MONTH [D]D, 'YY MONTH [D]D, YYYY MON. [D]D, YY MON. [D]D, 'YY MON. [D]D, YYYY MON [D]D, YY MON [D]D, 'YY MON [D]D, YYYY

這個正則表達式的誤報包括“Order 99, 99”,要消除這些誤報,可以將這個正則表達式與用於月份的正則表達式結合起來,如上所述,以便能夠僅匹配實際的月份名稱。另外,更改數值范圍以避免錯誤的匹配,並且通過使逗號成為可選項,重復了 18 種可能的格式。

這將得到一個很長的正則表達式。嘗試下面的表達式:

"([^A-Za-z0-9])(Jan(uary \.)Feb(uary \.)Mar(ch \.) Apr(il \.)May( \.)Jun(e \.)Jul(y \.)Aug(ust \.) Sep(tember \.)Oct(ober \.)Nov(ember \.) Dec(ember \.)) [0-3]?[0-9]{1}(,)? ([0-9]{4}'?[0-9]{2})"

同樣,根據您的需要仔細設計正則表達式。匹配模式通常比較容易,這是因為它存在於特定輸入的上下文中,而不是因為它可能獨立於數據集而存在。後代人將會發現,前面那個很長的正則表達式中仍然存在 Y10K 錯誤,因為它能匹配的最大可能的年份為 9999。

匹配整數

正如您在前幾個示例中看到的,使用方括號中的范圍可以很好地匹配數值。

要匹配任意長度的整數,可以在數值范圍後面加上 +;要包括負值,可以在它的前面加上可選的負號(連字號)匹配:

-?[0-9]+

前面的例子可以匹配 0,因為 0 是指定范圍中可選的字符。

對於數值匹配,使用圓括號將某些部分括起來也非常有效。要匹配任意的十進制數值,可以使用包含小數點加上一個或多個數值的可選圍繞字符,以此對前面的正則表達式進行擴展:

-?[0-9]+(\.[0-9]+)?

可以使用方括號指定十進制數值的小數位數。例如,要匹配小數位數為 5 或更多小數位數的正數值,可以使用下面的表達式:

[^-][0-9]+\.([0-9]){5,}

更多實際的匹配

范圍加上使用括號括起來的元字符,在查找符合任何特定格式的數值時非常有用。將前面介紹的一些技術結合起來,可以構建匹配各種數據的正則表達式:

要匹配美國的電話號碼,可以使用:

((\([2-9][0-9]{2}\))?\ ?[2-9][0-9]{2}(?:\-?\ ?))[2-9][0-9]{2}[- ]?[0-9]{4}

這個正則表達式可以匹配美國 15 種格式的電話號碼:

(NPA) PRE-SUFF (NPA) PRE SUFF (NPA) PRESUFF (NPA)PRE-SUFF (NPA)PRE SUFF (NPA)PRESUFF NPA PRE-SUFF NPA PRE SUFF NPA PRESUFF NPAPRE-SUFF NPAPRE SUFF NPAPRESUFF PRE-SUFF PRE SUFF PRESUFF

它還可以匹配美國免費 WATS 號碼,盡管 1-800 的“1-”前綴或其他的免費號碼不是匹配的一部分,但它本身可以匹配 10 位的數值。對於以 1 或 1+ 開頭的美國號碼和任意數目的空格,也完全一樣,長途電話撥號前綴本身無法匹配,但是只要它後面跟著實際的號碼,這個正則表達式就能夠將其找出來。

要匹配兩或三位域的電子郵件地址,可以嘗試下面的表達式:

\<[^@]+\>@[a-zA-Z_\.]+?\.[a-zA-Z]{2,3} 要匹配如今所有流行的 URL,可以使用下面的正則表達式:

(((http(s)?FTPtelnetnews)://mailto:)[^\(\)[:space:]]+)

這個表達式可以正常運行,但是匹配 URL 並不像您想象的那麼簡單。匹配任何可能的 URL 的正則表達式,如 RFC 1738 中的定義,發表在“Regexp for URLs”(請參見參考資料部分)一文中,它非常巨大並且看起來令人生畏。現在應該將它合並為一個 [:url:] 類(如果有用於處理類似數據種類的各種新的類,如 [:email:],那就好了)。

結束語

本文涉及到一些用於編寫正則表達式的模式構建技術,以及如何使用它們來完成管理員時常碰到的特定類型數據匹配的工作。在此過程中,向您介紹了大量有價值的實際正則表達式,您可以將它們添加到自己的管理工具庫中。




Copyright © Linux教程網 All Rights Reserved