讀古今文學網 > 精通正則表達式(第3版) > 作為編程語言的正則表達式 >

作為編程語言的正則表達式

Regular Expressions as a Language

如果沒有正則表達式相關經驗,讀者可能無法理解上個例子中正則表達式「^(From|Subject):」的意義,但是這個表達式並沒有什麼神奇之處。其實魔術本身也不神奇,只是缺乏訓練的普通觀眾不明白魔術師掌握的那些技巧而已。如果你也懂得如何在手中藏一張牌,那麼,熟練之後,你也可以「變魔術」。外語也是這樣——一旦掌握了一門外語,你就不會覺得它像天書了。

以文件名做類比

The Filename Analogy

選擇這本書的讀者,大概對「正則表達式」 多少有點認識。即便沒有,也應該熟悉其中的基本概念。

我們都知道,report.txt是一個文件名,但是,如果你用過Unix或者DOS/Windows的話,就會知道「*.txt」能夠用來選擇多個文件。在此類文件名(稱為「文件群組」file globs或者「通配符」wildcards)中,有些字符具有特殊的意義。星號表示「任意文本」,問號表示「任意單個字符」。所以,文件群組「*.txt」以能夠匹配字符的「*」符號開頭,以普通文字「.txt」結尾,所以,它的意思是:選擇以任意文本開頭,以.txt結尾的所有文件。

大多數系統都提供了少量的附加特殊字符(additional special characters),但是,總的來說,這些文件名模式(filename patterns)的表達能力還很有限。不過,因為這類問題的領域很狹窄——只涉及文件名,所以這算不上缺陷。

不過,處理普通的文本就沒有這麼簡單了。散文、詩、程序代碼、報表、HTML、表格、單詞表……到你想得出的任何文本。如果某種特殊的需求足夠專業,例如「選擇文件」,我們可以發明一些特殊的辦法和工具來解決問題。不過,近年來,一種「通用的模式語言」(generalized pattern language)已經發展起來,它功能強大,描述能力也很強,可以用來解決各種問題。不同的程序以不同的方式來實現和使用這種語言,但是綜合來說,這種功能強大的模式語言和模式本身被稱為「正則表達式」(regular expression)。

以語言做類比

The Language Analogy

完整的正則表達式由兩種字符構成。特殊字符(special characters,例如文件名例子中的*)稱為「元字符」(metacharacters),其他為「文字」(literal),或者是普通文本字符(normal text characters)。正則表達式與文件名模式(filename pattern)的區別就在於,正則表達式的元字符提供了更強大的描述能力。文件名模式只為有限的需求提供了有限的元字符,但是正則表達式「語言」為高級應用提供了豐富而且描述力極強的元字符。

為了便於理解,我們可以把正則表達式想像為普通的語言,普通字符對應普通語言中的單詞,而元字符對應語法。根據語言的規則,按照語法把單詞組合起來,就會得到能傳達思想的文本。在 E-mail 的例子中,我用正則表達式來尋找以『From:』或者『Subject:』開頭的行。下畫線標注的就是特殊字符,稍後我們將解釋它們的含義。

就像學習任何一門外語一樣,第一眼看上去,正則表達式很不好理解。這也是那些對它只有粗淺瞭解或者根本不瞭解的人覺得正則表達式很神奇的原因。但是,就像學日語的人很快就能理解正規表現簡簡!(注 2)一樣,讀者很快也能夠徹底明白下面這個正則表達式的含義:

s!<emphasis>([0-9]+(\.[0-9]+){3})</emphasis>!<inet>$1</inet>!

這個例子取自一個 Perl 腳本,我的編輯器用它來修改手稿。手稿的作者錯誤地使用了<emphasis>這個tag來標注IP地址(類似209.204.146.22這樣由數字和點號構成的字符串)。其中的奧妙就在於使用Perl的文本替換命令,使用:

「<emphasis>([0-9]+(\.[0-9]+){3})</emphasis>」

把IP地址兩端的tag替換為<inet>,而不改動其他的<emphasis>標籤。在後面的章節中,讀者會瞭解這個表達式的構造細節,然後就能按照自己的需求,在自己的應用程序或者開發語言中應用這些技巧。

本書的目的

你或許不需要重複把<emphasis>替換為<inet>的工作,不過很可能需要解決「把這些文字替換為那些文字」的問題。本書的目的不是提供具體問題的解決辦法,而是教會讀者利用正則表達式來思考,解決遇到的各種問題。