刨根究底正則表達式之一——正則表達式簡介


說明:

雖然本系列文章開篇會簡單介紹正則表達式的一些基礎知識,但主要限於本系列文章所想強調的要點,因此本系列文章並不適合用於入門

若你是對正則表達式沒有任何概念的初學者,建議至少先閱讀網上備受推崇的《正則表達式30分鍾入門教程》,時間允許的話最好再閱讀《正則表達式必知必會》(才130多頁,寫得非常基礎,快的話一天可輕松讀完)。這樣在建立了對正則表達式的基本認識之后,再來閱讀本系列文章,才更為合適。

最后,文中若有錯漏,還請直接招呼板磚,不用客氣😊

正則表達式簡介

                       

一、正則表達式概念

一)先從“通配符”說起

1.

對於初學者而言,正則表達式,僅從字面上來說不太好理解。但實際上,您可能早已經使用過了某些正則表達式的功能,只是自己還沒有意識到而已。

例如,您很可能使用過?和*這兩個通配符來查找硬盤上的文件。?通配符匹配文件名中的單個字符,而*通配符匹配零個或多個字符。像“data?.dat”這樣的匹配模式將可以匹配查找到下列文件名:

data1.dat

datax.dat

dataN.dat

使用*字符代替?字符可以擴大所能找到的文件數量。比如“data*.dat”可以匹配下列所有文件名:

data.dat

data1.dat

data12.dat

datax.dat

dataXYZ.dat

2.

因此,所謂“通配符”,即“通用匹配字符”,就是用某個通用字符按事先所規定的規則來查找匹配某些常規字符,從而實現“以一對多”(或“以一代多”)、“以簡對繁”(或“以簡代繁”)地簡化、抽象化、通用化用來進行查找匹配的表達式的目的。

然而,盡管使用“通配符”的匹配查找方法很有用,但它的功能還是非常有限的。和通配符類似,正則表達式也是用來進行文本匹配查找的工具。只不過相比通配符而言,正則表達式更為抽象化、通用化,功能也更為強大、更加靈活,能夠更為精確地表達匹配條件(即匹配規則),當然也就更復雜,更難以學習和掌握。

笨笨阿林原創文章,轉載請注明出處)

二)正則表達式概念

1.

正則表達式,又稱正規表示法、常規表示法(Regular Expression,在代碼中常簡寫為regex、regexp或RE),計算機科學的一個概念。

正則表達式是一種字符串的匹配模式,描述的是某一類字符串的共同特征。

2.

所謂模式,就是模板樣式或模具樣式。正如符合某種樣式的模板或模具,可以用來生產符合這種樣式的同一類產品一樣;反過來,也可以用某種樣式的模板或模具,來檢驗或框定哪些產品才是符合這種樣式的同一類產品。

正則表達式正是類似於這樣的模板或模具,用來檢驗或框定哪些字符串是符合正則表達式所描述的字符串共同特征的同一類字符串;而這個檢驗或框定的過程,就稱之為匹配

3.

我們平時所使用的自然語言中,可以用“漂亮”、“堅固”、“挺拔”等高度抽象性詞語來描述事物的共同特征一樣,一個正則表達式正是某一類字符串的高度抽象,用來描述這類字符串的共同特征。也就是說,一個正則表達式代表了某類字符串的一個集合,而正則表達式相當於對該字符串集合的特征性質描述。(注:集合的常用表示方法有元素列舉法、特征性質描述法和圖示法。)

正則表達式還可看作是對字符串操作的一種邏輯公式,其構造方法和創建數學表達式的方法差不多,也就是用普通字符(如字母a到z、數字0到9等)和事先定義好的一些特定字符(專業術語稱之為元字符),以及這些字符的組合,組成一個特定的規則字符串。而所謂特定的規則,即是正則;因此特定的規則字符串,即是正則表達式。

這些“特定的規則”,從被匹配的字符串的角度上來看,可以認為描述的是某一類字符串的共同特征;而從正則表達式的角度上來看,也可以認為表達的是一種匹配規則(或稱過濾邏輯)

4.

因此,正則表達式是一種特殊的字符串(即正則表達式字符串,往往直接簡稱為正則表達式或正則式),用來描述、匹配、過濾符合某些特征的其它字符串(即輸入字符串、源字符串、被測試的字符串、被匹配的字符串,往往直接簡稱為字符串)

說某個正則表達式匹配某個字符串,通常是指這個字符串的全部或一部分或幾部分分別符合或者說滿足正則表達式所描述的字符串特征;也可以說是指這個字符串的全部或一部分或幾部分分別符合或者說滿足正則表達式所規定的匹配條件或匹配規則。

笨笨阿林原創文章,轉載請注明出處)

5.

而從正則表達式作為一種編程語言的角度上來看,正則表達式的基本語法結構與一般高級編程語言差不多,主要就是順序(即連接)、選擇(即分支)、循環(即重復)三種,其他都是這三者的組合,再加上一些語法糖。

再更進一步地,從正則表達式作為一個聲明式編程范式的領域特定語言DSL的角度來講,正則表達式的順序、選擇、循環這三種基本語法結構是非常簡潔、緊湊的(這幾乎是聲明范式DSL的基本特點,而正則表達式將這一點體現得尤為淋漓盡致)。其中,連接無需通過元字符表示,選擇通過元字符“|”表示,而循環則通過元字符“*”、“+”或“{n,m}”表示。這三種基本語法結構在使用時,直接進行聲明式描述即可,無需通過復雜的語句來進行算法設計。

事實上,還可從編程語言操作符(即運算符)的角度來理解,其中,“*”、“+”或“{n,m}”是單目后綴操作符,“|”是雙目中綴操作符,連接其實也是雙目中綴操作符,不過是隱含的(即隱式的,因為連接是三種基本語法結構中最常用的,所以設計為隱式操作符最為合理)。

 

二、正則表達式功能

1.

一般而言,典型的簡單搜索和替換操作,可通過直接提供與預期的搜索結果相匹配的字面文本來實現。雖然這種方法對於文本執行簡單的、靜態的搜索和替換任務可能已經足夠了,然而卻缺乏足夠的靈活性和動態性。

若通過使用正則表達式,則可以:

    • 查找文本

查找符合某一正則表達式的文本,尤其是查找符合某一正則表達式的非固定文本,比如查找符合某一種模式(甚至長度不定)的文本。

    • 提取文本

可以查找字符串內符合某個文本模式的文本(子字符串),然后將其提取出來以備他用。

    • 驗證文本

所謂驗證文本,是指檢査文本能否完全由正則表達式匹配,主要用來測試和保證數據文本的合法性。

例如,可以測試輸入字符串,以查看字符串內是否出現電話號碼模式(比如0XXX-XXXXXXXX這樣的模式:必須為0開頭,接着3位數字、短橫杠、8位數字)。

    • 替換文本

可以使用正則表達式所表示的文本模式來識別、匹配文檔中符合該文本模式的所有文本(即符合該文本模式的文本的集合),而不只是識別、匹配某個特定的、確切的文本(比如0XXX-XXXXXXXX就是電話號碼模式,而0755-88888888就是某個特定的、確切的電話號碼),然后可以完全刪除匹配該文本模式的所有文本(相當於用空字符串替換)或者用其他文本逐一進行替換。

    • 切分文本

切分也是正則表達式的常見操作之一,切分操作一般以正則表達式匹配的文本作為間隔,將字符串切分成多個片段(即子字符串)。

2.

顯然,通過使用文本模式,正則表達式相比較於直接使用固定的、明確的字面文本進行簡單的、靜態的搜索和替換,更為靈活,也更具有動態適應性。而且,正則表達式同樣也可以使用字面文本進行簡單的、靜態的搜索和替換(當然,這有點大材小用了,效率也比直接搜索和替換更低,因此,字面文本的直接搜索和替換,不推薦使用正則表達式)。

因此,正則表達式的熟練運用,是文本處理人員,尤其是編程人員的必備技能。其強大的功能、快捷的速度,一旦掌握,你將會既嘆服於心,又享受其中。

 

三、正則表達式簡史

1.

正則表達式的“祖先”可以一直追溯至對人類神經系統如何工作的早期研究。Warren McCulloch和Walter Pitts這兩位神經生理學家在20世紀40年代研究出用一種數學方式來描述神經網絡。

1956年,一位叫Stephen Kleene的數學家在McCulloch和Pitts早期工作的基礎上,發表了一篇標題為《神經網絡事件表示法和有窮自動機(Representation of events in nerve nets and finite automata)》的論文,引入了正則表達式的概念。正則表達式就是用來描述他稱為“正則集合Regular Sets”的表達式,這就是“正則表達式”這個術語的來源。

2.

隨后,大名鼎鼎的Unix之父——Ken Thompson於1968年發表了文章《正則表達式搜索算法(Regular Expression Search Algorithm)》,並且將正則表達式這一符號系統引入了他自己開發的編輯器qed以及之后的編輯器ed中,然后又被移植到了大名鼎鼎的文本搜索工具grep中。自此,正則表達式被廣泛應用到各種Unix系統或類Unix系統(如Mac系統、Linux系統)的工具中。

由於正則表達式異常強大而實用的功能,越來越多的語言和工具引入了正則表達式。不過遺憾的是,始終沒有確立正則表達式方面的標准,導致各語言與工具中的正則表達式雖然功能上大體類似,但細微差別仍然不少。於是,誕生於1986年的POSIX開始進行標准化的嘗試。

笨笨阿林原創文章,轉載請注明出處)

3.

POSIX,是Portable Operating System Interface for uniX(可移植Unix操作系統接口)的縮寫。POSIX是一系列規范,定義了Unix操作系統應當支持的功能,其中也包括正則表達式的規范。

因此,Unix系統或類Unix系統上的大部分工具,如grep、sed、awk等,均遵循該標准。遵循POSIX正則表達式規范的這些語言和工具中的正則引擎,往往習慣將它們稱之為POSIX流派的正則引擎。

4.

之后,1988年6月,Larry Wall開發的Perl語言發布第2版,其中所引入的正則表達式引擎大放異彩。Perl 2的正則表達式引擎源於Henry Spencer編寫的regex的增強版。之后不斷改進,影響越來越大。於是在此基礎上,1997年又誕生了PCRE——Perl兼容正則表達式(Perl Compatible Regular Expressions)。

PCRE是一個由Philip Hazel開發的、為很多現代語言和工具所普遍使用的Perl正則表達式兼容引擎,現已成為除了Unix上的工具所遵循的POSIX標准之外的其他大部分語言和工具所隱然遵循的另一個事實上的標准。因此,往往習慣將這些Perl正則表達式兼容引擎稱之為PCRE流派的正則引擎。

POSIX流派與PCRE流派是目前正則表達式引擎流派中的兩大最主要的流派。

之后,正則表達式在各種計算機語言或各種應用領域進一步得到了更為廣泛而普遍的應用和發展。


Perl語言之父 Larry Wall

 

四、正則表達式流派

1.

如前所述,目前正則表達式主要有兩大流派(Flavor):POSIX流派與PCRE流派。

1) POSIX(Portable Operating System Interface for uniX)流派

POSIX是一系列規范,定義了UNIX操作系統應當支持的功能,其中也包括正則表達式的規范。POSIX規范的正則表達式流派是PCRE之外的另一大流派。

POSIX規范定義了正則表達式的BRE(Basic Regular Expression基本正則表達式)和ERE(Extended Regular Express擴展正則表達式)兩種標准。早期,BRE與ERE的區別主要在於:

不過,后來隨着BRE與ERE逐漸相互融合,現在的BRE和ERE(包括GNU改進的GNU BRE和GNU ERE)在功能特性上並沒有太大區別,主要的差異是在元字符的轉義上。

在遵循POSIX規范的UNIX/LINUX系統上,vi/vim、grep和sed遵循POSIX規范的BRE標准,egrep、awk則遵循ERE標准。這些UNIX/LINUX系統常用工具的正則表示法與PCRE對比如下:

1vim中的\?和\=都表示匹配0或1個前面的子表達式,但\?不能在反向查找的“?”命令中使用。

2vim中的右花括號}之前可以不加反斜杠,也可以加反斜杠,比如:\{n,m\}。

3PCRE中常用\b來表示“單詞的起始或結束位置”,但Linux/Unix的工具中,通常用\<來匹配“單詞的起始位置”,用\>來匹配“單詞的結束位置”,而sed中的\y則與PCRE中的\b一樣,可同時匹配這兩個位置。

2) PCRE(Perl Compatible Regular Expression)流派

目前大部分常用編程語言中常見的正則表達式語法,其實都源於Perl。其中,PCRE就是從Perl衍生出來的最為著名的一個流派,\d、\w、\s之類的字符組簡記法,是這個流派的顯著特征。

不過,雖然PCRE是從Perl語言中衍生出來的,但與Perl語言的正則表達式還是有一些細微差異的,比如PHP的preg(Perl Regular Expression)與Perl的差異可看這里

注:PHP支持兩種不同的正則引擎:ereg與preg,ereg全稱為Extended Regular Expression,屬於POSIX ERE;ereg由於功能方面的不足,已經逐漸被preg替代了,ereg將在未來被廢棄。因此,若非特別說明,后文中當提到PHP正則引擎時,默認指的是PHP preg正則引擎。)

考慮到目前絕大部分常用編程語言所采用的正則引擎基本屬於PCRE流派,因此,本系列文章將以PCRE流派為主、以POSIX流派為輔進行介紹;文中有關各語法元素的解釋,若非特別說明,均以PCRE流派為准。

2.

另外,如前所述,當我們在介紹正則表達式的流派時,與Perl正則規范相兼容(包括直接兼容與間接兼容)的流派習慣用PCRE來稱呼。

而本系列文章在介紹與Perl正則規范直接兼容(但除Perl外並非完全兼容)的語言或正則庫或工具程序,比如Perl、PHP preg、PCRE庫時,一般稱之為Perl系;與之對應的還有間接兼容的Java系(包括Java、Groovy、Scala等)、.Net系(包括C#、VB.Net)、Python系(包括Python2和Python3)、JavaScript系(包括原生JavaScript和擴展庫XRegExp)等等。

也就是說,Perl系、Java系、.Net系、Python系、JavaScript系(另外還有Ruby、C++Builder、Delphi等)均屬於PCRE流派,但與Perl的兼容性(即兼容程度)各有不同。其中,Perl系兼容性最好,雖然PHP preg與PRCE庫並非與Perl完全兼容,但基本兼容,因此屬於直接兼容;而其他語言或工具相對Perl系而言,與Perl的兼容性較差,則屬於間接兼容。

笨笨阿林原創文章,轉載請注明出處)

 

參考資料:

一)官方文檔

Perl:

Perl regular expressions (perlre)(英文)

Perl Regular Expressions Reference (perlreref)(英文)

Perl Regular Expression Backslash Sequences and Escapes (perlrebackslash)(英文)

Perl Regular Expression Character Classes (perlrecharclass)(英文)

PCRE:

pcre2 syntax man page(英文)

PHP:

PCRE(preg)正則表達式語法介紹(中文)

.Net(C#、VB):

正則表達式語言快速參考(中文)

Java:

Regular Expressions Tutorials(英文)

Package java.util.regex(英文)

JavaScript:

MDN:正則表達式簡介(中文)

MDN:RegExp對象說明(中文)

EMCAScript:RegExp (Regular Expression) Objects(英文)

Python2.7:

正則表達式操作(中文)

Regular expression operations(英文)

Python3.4:

Regular expression operations(英文)

Regular expression HOWTO(英文)

Ruby:

Regular Expressions(英文)

Vim:

模式及查找命令 For Vim version 7.4(中文)

Search commands and patterns For Vim version 7.3(英文)

GNU Grep:

Regular Expressions(英文)

GNU Sed:

Regular Expressions(英文)

GNU awk:

Regular Expressions(英文)

二)書籍

精通正則表達式》英文版及中文版 作者:Jeffrey E·F·Friedl 譯者:余晟 電子工業出版社 2012-07

正則指引》作者:余晟 電子工業出版社 2012-05

正則表達式必知必會》作者:Ben Forta譯者:楊濤 人民郵電出版社2015-01

冒號課堂:編程范式與OOP思想》作者:鄭暉 電子工業出版社 2009-10

三)其他

本系列文章還參考了網上的大量資料,除了少部分資料由於未作大量修改(但基本上也有少量修改,因為網上文章隨意性較大,很多明顯的筆誤或前后矛盾之處,如若不改反而讓人迷糊)而標明了原作者和出處之外,其余由於基本上已按自己的理解作了大量改寫,因此沒有再一一予以說明,在此對原文作者表示歉意並感謝。

另外,文中圖片小部分來自網絡,大部分為本人制作,也不再一一說明,在此對原圖作者表示歉意並感謝。

(未完待續)

 

本系列文章上一篇為:刨根究底正則表達式之零——前言 

 

預告:本系列文章下一篇為正則表達式基礎與八大原則簡介,敬請關注!】

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM