1. 程式人生 > 其它 >分鐘學會正則表示式(譯)

分鐘學會正則表示式(譯)

正則表示式(“regexes”)即增強查詢/字串替換操作。當在文字編輯器中編輯文字時,正則表示式經常用於:

  • 檢查文字是否包含一個給定的模式
  • 查詢任何匹配的模式
  • 從文字中拉取資訊(比如截斷)
  • 修改文字

和文字編輯器一樣,絕大多數高階程式語言支援正則表示式。在本文中,“文字”僅僅是一個字串變數,但是有效的操作卻是一致的。某些程式語言(Perl,JavaScript)甚至為正則表示式提供專用的語法。

但是正則表示式是什麼?

一個正則表示式僅僅為一個字串。它沒有長度限制,但是通常該字串很短。下面看幾個例子:

  • I had a S+ day today
  • [A-Za-z0-9-_]{3,16}
  • dddd-dd-dd
  • v(d+)(.d+)*
  • TotalMessages="(.*?)"
  • <[^<>]>

這個字串實際上是一個極小的計算程式,並且正則表示式是一門語法小而簡潔,領域特定的程式語言。牢記以下幾點,它們不該在學習過程中讓你感到驚訝:

  • 每個正則表示式都能分解成一串指令。“找到這個,再找到那個,然後找到其中一個...”
  • 一個正則表示式擁有輸入(文字)和輸出(模式匹配,和有些時候的自定義文字)。
  • 存在語法錯誤——不是每個字串都是合法的正則表示式!
  • 語法有些怪異,也可以說是恐怖。
  • 一個正則表示式有時候可以被編譯以便更快執行。

正則實現一直有著顯著的改變。對於本文,我所關注的是那些幾乎每個正則表示式都實現了的核心語法。

練習

獲取一個支援正則的文字編輯器。我推薦Notepad++。

下載一篇很長的散文故事比如Gutenberg出版社出版的H. G. Wells的《時光機器》然後開啟它。

下載一部字典,比如這個,解壓然後開啟。

一切準備就緒,稍後開始練習。

提示:正則表示式與檔案萬用字元語法完全不相容,比如*.xml

正則表示式基礎語法

字面值(Literals)

正則表示式由只代表自身的字面值和代表特定含義的元字元組成。

這裡也有一些例子。我會對元字元進行高亮。

  • I had aS+day today
  • [A-Za-z0-9-_]{3,16}
  • dddd-dd-dd
  • v(d+)(.d+)*
  • TotalMessages="(.*?)
    "
  • <[^<>]*>

大部分字元,包括字母數字字元,會以字面值的形式出現。這意味著它們查詢的是自身。比如,正則表示式cat代表“先找到c,接著找到a,最後找到t”。

目前為止感覺良好。這的確很像

  • 一個普通的查詢對話方塊
  • Java中的String.indexOf()函式
  • PHP中的strpos()函式
  • 等等

提示:除非特別說明,正則表示式是區分大小寫的。然而,絕大多數實現都會提供一個標記來開啟不區分大小寫的功能。

句點(dot)

我們第一個元字元是句號(譯者注:句點,英文句號),.。一個.表示匹配任何單個字元。下面這個正則表示式c.t代表“先找到c,接著找到任何單個字元,再找到t”。

在一段文字中,這個表示式將會找到catcotczt,甚至字面值為c.t的字串(c,句點,t),但是不包括ct或者coot

在正則表示式裡,空格是有效的。正則表示式 'c t' 代表”先找到 'c',接著找到空格,再找到 't'“。

任何元字元如果用一個反斜杆進行轉義就會變成字面值。所以上述的正則表示式c.t就代表“先找到c,接著找到句號,再找到t”。

反斜槓是一個元字元,這意味著它也可以使用反斜槓轉義。所以正則表示式ct代表“先找到c,接著找到反斜杆,再找到t”。

注意!在一些實現中,.會匹配除了換行符的任意字元。這意味著“換行符”在不同的實現中也會變化。 要檢視你的文件。在這篇文章中, 我會確保.會匹配任意字元。

在其它情況下, 通常會有一個標記來調整這種行為,那就是`DOTALL`或類似的標記

練習

使用你目前所學,在字典中使用正則表示式,匹配一個有兩個z的單詞,其中這兩個z離得越遠越好。

練習

《時光機器》這本書中,使用正則表示式來查詢以介詞收尾的句子。

字元類(Character classes)

字元類是字元在方括號中的集合。表示“找到集合裡任意一個字元”。

  • 正則表示式c[aeiou]t表示“找到c後跟一個母音字母,再找到t”。在一段文字中,將會匹配到catcetcitcotcut
  • 正則表示式[0123456789]表示找到一個數字
  • 正則表示式[a]a意義相同:“找到a

一些轉義的例子:

  • [a]表示“找到一個左方括號緊跟著一個a,再跟著一個右方括號”。
  • [[]ab]表示“匹配一個左方括號或者右方括號或者a或者b”。
  • [[]]表示“匹配一個反斜杆或者一個左方括號或者一個右方括號”。(嘔!)

在字元類中順序和重複字元並不重要。[dabaaabcc][abcd]一樣。

重要的提示

在字元類內部的“規則”和在字元類內部的規則有所不同。一些字元在字元類內部扮演著元字元的角色,但在字元類外部則充當字面值。還有一些字元做著相反的事。一些字元在兩種情形都為元字元,但在各自情形裡代表不同的含義。

特別地,.表示“匹配任意字元”,但是[.]表示“匹配句點”。不能併為一談。

練習

結合目前所學,在字典中,使用正則表示式查詢有連續的母音和連續的子音的單詞。

字元類區間(ranges)

你可以在字元類中使用連字元來表示一個字母或數字的區間

  • [b-f][bcdef]都表示“找到一個bcdef”。
  • [A-Z][ABCDEFGHIJKLMNOPQRSTUVWXYZ]都表示“匹配大寫字母”。
  • [1-9][123456789]都表示“匹配一個非零數字”。

連字元在字元類外部使用時並沒有特別都含義。正則表示式a-z表示“找到一個a接著跟著一個連字元,然後匹配一個z”。

區間和單獨的字元可能會共存於吥