閱讀172 返回首頁    go 阿裏雲 go 技術社區[雲棲]


《正則表達式經典實例(第2版)》——第 1 章 正則表達式簡介 1.1正則表達式的定義

本節書摘來自異步社區《正則表達式經典實例(第2版)》一書中的第1章,第1.1節,作者: 【美】Jan Goyvaerts , Steven Levithan著,更多章節內容可以訪問雲棲社區“異步社區”公眾號查看

第 1 章 正則表達式簡介

在你打開這本書的時候,很可能已經熱切地期望,要在代碼中插入本書中找到的那些包含諸多括號和問號的古怪字符串了。如果你已經準備好要“即查即用”,我們非常歡迎,第4~9章中會列出並講解了各種實用的正則表達式。

但是如果閱讀本書的前幾章,你將為未來節省大量的時間。例如,本章會向讀者介紹許多工具—其中一些工具是本書作者之一的Jan所開發的,這些工具可以幫你事先測試和調試正則表達式,而不用等到把它們塞到代碼中之後再處理,那時候查找錯誤就非常困難了。而且開始這幾章還會展示使用正則表達式的不同特性和選項,幫助你輕鬆應對遇到的問題,並幫助你理解正則表達式,從而提高它們的性能,以及學習不同語言—甚至是你最喜歡的編程語言的不同版本之間—在處理正則表達式的時候出現的細微差別。

因此,我們在這些背景知識上花費了大量的精力,相信讀者在開始動手之前會閱讀這些內容,或是在使用正則表達式時遇到挫折,而想要鞏固你的理解的時候,會回頭來閱讀它們。

1.1 正則表達式的定義

在本書的上下文中,正則表達式(regular expression)是一種可以在許多現代應用程序和編程語言中使用的特殊形式的文本模式。它們可以用來驗證輸入是否符合給定的文本模式;在一大段文本中查找匹配該模式的文本;用其他文本來替換匹配該模式的文本或者重新組織匹配文本的片段;把一塊文本切分成一係列更小的文本,當然如果使用不當也可能搬起石頭砸自己的腳。本書會幫助你確切理解正在做的事情,從而避免可能會造成的災難性後果。

學會了使用正則表達式的技巧,就可以簡化許多編程和文本處理的任務,並且讓許多沒有正則表達式則根本無法實現的任務成為可能。從一個文檔中提取所有的電子郵件地址,至少需要幾十行,甚至是幾百行過程式代碼—這些代碼編寫起來費事,維護起來也麻煩。但是,如果采用了合適的正則表達式,如在實例4.1中所給的那樣,就隻需要很少的幾行甚至隻要一行代碼就可以了。

術語“正則表達式”的曆史

術語“正則表達式”來源於數學與計算機科學理論,它用來反映被稱為“正則性”的數學表達式特點。這樣一個表達式可以通過一個確定性有限自動機(DFA)用軟件來實現。一個DFA是一個不使用回溯的有限狀態機。

最早版本的grep工具所使用的文本模式是數學意義上的正則表達式。盡管名字看起來是一樣的,然而如今流行的Perl風格的正則表達式已經完全不是數學意義上的正則表達式了。它們是采用非確定性的有限自動機(NFA)來實現的。你稍後就會學到和回溯有關的所有內容。關於這條說明,實幹的程序員需要記住的所有內容就是:象牙塔裏的一些計算機科學家,很不喜歡自己精心定義的術語被套用到現實世界中更為有用的技術。
但是,如果你試圖用一個正則表達式來做太多的事情,或者是在根本不適合的情形中非要使用正則表達式,就會明白為什麼會存在如下的說法1FF:

有些人每遇到一個問題,就會想“我知道怎麼做,用正則表達式就可以了。”於是他們就有兩個(而不是一個)問題需要解決了。
這些人所遇到的新問題指的就是他們並不會去閱讀用戶手冊,也就是現在你手裏的這本書。所以請繼續讀下去。正則表達式是一個強大的工具。如果你的工作涉及在計算機上編輯或是提取文本,牢固地掌握正則表達式就會為你少度過很多個不眠之夜。

1.1.1 眾多正則表達式流派
上一小節的標題確實表述得不那麼確切,我們並沒有定義正則表達式到底是什麼。我們也不可能給出定義。對於哪些文本模式是正則表達式,而哪些不是,並不存在正式的標準來給出嚴格精確的定義。可以想象得到,每種編程語言的設計人員,以及每款文本處理程序的開發人員,對於正則表達式應該是什麼樣子,都會有自己不同的想法。因此,我們就不得不麵對這樣一大堆不同的正則表達式流派。

幸運的是,絕大多數設計人員與開發人員都比較懶惰。如果可以照搬別人已經做好的工作,為什麼非要自己創建一些全新的東西呢?正因為此,所有現代的正則表達式流派,包含本書要討論的這些流派,其曆史都可以追溯到Perl編程語言。我們把這些流派都稱作Perl風格的正則表達式。它們的正則表達式語法都非常相似,而且在大多數情況下是相互兼容的,但也不是完全如此。

作家也都很懶。在本書中,我們通常會使用regex或regexp來指代一個單個的正則表達式,而使用regexes來指代其複數形式2。

正則流派並不是和編程語言一一對應的。腳本語言傾向於擁有它們自己內置正則表達式流派,其他語言則會依賴於函數庫來提供正則表達式支持。有些函數庫是對多種語言可用的,而某些特定的語言則會選用一些不同的函數庫。

本章要講解的內容隻與正則表達式的流派有關,因此會徹底忽略任何與編程有關的考慮事項。從第3章開始,我們會給出一些代碼片段,所以你可以先跳到第3章的第一節,以了解你將會使用哪些流派。但是現在請先忽略所有與編程相關的內容。下麵一小節中列出的工具將會通過“動手學習”的方式,讓你更方便地探索正則表達式的語法。

1.1.2 本書涵蓋的正則流派
在本書中,我們選擇了如今最為流行的正則流派。這些都是Perl風格的正則流派。有些流派會比其他流派多一些特性。但是如果兩種流派擁有同一個特性的話,那麼它們通常都會使用相同的語法。當然也會有例外,當我們遇到這些煩人的不一致情況時,在書中會加以提示。

所有這些正則流派都屬於目前正在活躍開發中的編程語言和函數庫的一部分。下麵的流派列表會告訴你本書所用到的是哪些版本。在本書後麵,如果所講解的正則表達式在所有流派中效果都一樣,那麼我們在提到該流派時就不會區分其版本。絕大多數場合都是這種情況。除了會影響到一些邊界情況的bug修複之外,正則表達式流派一般都不會改變,唯一例外是添加新的特性,原來認為是錯誤的語法,現在會被賦予新的含義。

.NET

微軟公司的.NET框架通過System.Text.RegularExpressions包,提供了一個功能全麵的Perl風格正則流派。本書涵蓋了.NET 1.0~4.0版。而嚴格來講,.NET正則流派隻存在兩個版本:1.0和2.0版。在 .NET 1.1、3.0和3.5版本中,並沒有對正則類進行任何修改。.NET 4.0的正則類有一些新方法,但沒有改變正則語法。
任何.NET編程語言,包括C#、VB.NET、Delphi for .NET,甚至包括COBOL.NET,都可以完整使用.NET正則流派。如果一個使用.NET開發的程序提供了正則表達式支持,即使它號稱使用的是“Perl正則表達式”,你也可以非常確定它使用的就是.NET正則流派。很長時間裏,令人大跌眼鏡的一個例外則是Visual Studio(VS)自身。直到Visual Studio 2010,VS集成開發環境(IDE)中依然使用的是它從一開始就在用的一個老版本的正則流派,而這個實現根本就不是Perl風格的。本書寫作時正處於測試版的Visual Studio 113FF,最終也在IDE中使用了.NET正則流派。

Java

Java 4是通過java.util.regex包提供內置正則表達式支持的第一個Java版本。這個包很快就超越了各種第三方Java正則庫。除了它是標準的和內置的之外,它還支持了功能完整的Perl風格正則流派,其卓越的性能甚至可以媲美使用C語言編寫的正則程序。本書會講解Java 4、5、6和Java 7中的java.util.regex包。如果你在過去幾年中用過Java語言開發的軟件的話,那麼其支持的正則表達式很可能是Java流派。

JavaScript

在本書中,我們使用JavaScript這個術語指代在ECMA-262標準的第3版和第5版中定義的正則表達式流派。這個標準定義了ECMAScript編程語言,而這個語言更廣為人知的是它在不同網頁瀏覽器中的JavaScript與JScript實現。Internet Explorer(自5.5版)、Firefox、Opera與Safari都實現了ECMA-262的第3版或第5版。盡管在正則表達式功能方麵,JavaScript 3與JavaScript 5的區別很小。然而,所有的瀏覽器都擁有各種與標準不同的邊界情形bug。我們會在必要的地方指出這些問題。

如果一個網站允許使用正則表達式進行查找或者過濾,並且不用等待網站服務器的響應,那麼它使用的就是JavaScript正則流派,這是唯一的跨瀏覽器客戶端正則流派。即使是微軟的VBScript與Adobe公司的ActionScript 3使用的也是它,不過ActionScript 3添加了一些額外特性。

XRegExp

XRegExp是Steven Levithan開發的開源JavaScript庫,可以從https://xregexp.com下載它。XRegExp擴展了JavaScript的正則表達式語法,並且消除了一些Web瀏覽器間的不一致。本書中的實例在用到標準JavaScript不支持的正則表達式特性時,會附加使用XRegExp的解決方案。如果一個解決方案的正則流派中列出了XRegExp,就意味著這個解決方案在JavaScript代碼中使用XRegExp庫時可以正常工作,而不使用XRegExp的標準JavaScript代碼無法正常工作。如果一個解決方案的正則流派中列出了JavaScript,則意味著無論JavaScript代碼中是否使用XRegExp,都可以正常工作。

本書涵蓋了XRegExp 2.0版。所有實例都假設讀者使用的是包含全部XRegExp Unicode特性的xregexp-all.js。

PCRE

PCRE是由Philip Hazel開發的“與Perl兼容的正則表達式” (Perl-Compatible Regular Expressions)的C語言函數庫。這個開源代碼庫可以從https://www.pcre.org下載。本書涉及的PCRE版本包括第4版到第8版。

雖然PCRE號稱是與Perl兼容的,而且與本書中的其他流派相比,它也是與Perl兼容性最好的,但是實際上它也隻能稱為是“Perl風格”的正則流派。有些特性,比如Unicode支持,會與Perl稍微有些不同,並且不能像在Perl中所允許的那樣,把Perl代碼混合到你的正則表達式之中。

因為它采用了開源許可,並且擁有穩定可靠的實現,所以PCRE被應用到了許多編程語言和程序中。它被內置到PHP中,並且被包裝到了許多個Delphi的組件中。如果一個應用程序號稱它支持“與Perl兼容”的正則表達式,而卻沒有具體列出它實際使用的正則流派,那麼就很可能是PCRE。

Perl

Perl對於正則表達式的內置支持是正則表達式今天得以流行的主要原因。本書會涉及Perl 5.6、5.8、5.10、5.12和5.14版。上述每個版本都為Perl正則表達式語法添加了新的特性。當本書中標明某正則式在特定Perl版本中工作時,那該正則式可在該特定版本及本書所涉及的所有更新版本中正常工作。

許多應用程序和正則庫都號稱它們使用的是Perl或者與Perl兼容的正則表達式,而事實上它們僅僅是使用了Perl風格的正則表達式。它們使用與Perl相似的正則語法,但是所支持正則特性集並不重疊。最有可能的情形是,它們使用的是這一特性集中的正則表達式流派之一,而這些流派都是屬於Perl風格的。

Python

Python通過它的re模塊來支持正則表達式。本書會講到Python 2.4至3.2版。Python 2.4、2.5、2.6和2.7版間的區別非常小。Python 3.0增強了Python處理正則表達式中Unicode的能力。Python 3.1和3.2則沒有與正則相關的改進。

Ruby

與Perl語言類似,Ruby的正則表達式支持是Ruby語言自身的一部分。本書會涉及Ruby 1.8和Ruby 1.9。Ruby 1.8的默認編譯會使用由Ruby源代碼直接提供的正則表達式流派。而Ruby 1.9的默認編譯則會使用Oniguruma正則表達式庫。Ruby 1.8也可以編譯使用Oniguruma,而Ruby 1.9也可以編譯使用舊版本的Ruby正則流派。在本書中,我們會把原生Ruby流派稱為Ruby 1.8,而把Oniguruma流派稱為Ruby 1.9。

如果想測試一下你的站點使用的是哪個Ruby正則流派,可以嚐試用一下正則表達式‹a++›。Ruby 1.8會說這個正則表達式是非法的,因為它並不支持占有量詞(possessive quantifier),而它在Ruby 1.9中則會匹配一個或者多個字符a組成的字符串。

Oniguruma庫設計為與Ruby 1.8向後兼容,它隻是在其上添加了新的功能,而不會破壞已有的正則表達式。該實現甚至原樣保留了大家認為應該修改的功能,例如:它依然使用‹ (?m) ›表示“點號匹配換行符”,即使其他正則表達式流派使用的都是‹ (?s) ›。

最後更新:2017-06-02 19:33:04

  上一篇:go  數學編織家和他們軟軟的作品
  下一篇:go  小白學數據:小世界網絡中的大世界