說明:php
雖然本系列文章開篇會簡單介紹正則表達式的一些基礎知識,但主要限於本系列文章所想強調的要點,所以本系列文章並不適合用於入門。html
若你是對正則表達式沒有任何概念的初學者,建議至少先閱讀網上備受推崇的《正則表達式30分鐘入門教程》,時間容許的話最好再閱讀《正則表達式必知必會》(才130多頁,寫得很是基礎,快的話一天可輕鬆讀完)。這樣在創建了對正則表達式的基本認識以後,再來閱讀本系列文章,才更爲合適。java
最後,文中如有錯漏,還請直接招呼板磚,不用客氣😊python
1、正則表達式概念正則表達式
一)先從「通配符」提及算法
1.express
對於初學者而言,正則表達式,僅從字面上來講不太好理解。但實際上,您可能早已經使用過了某些正則表達式的功能,只是本身尚未意識到而已。編程
例如,您極可能使用過?和*這兩個通配符來查找硬盤上的文件。?通配符匹配文件名中的單個字符,而*通配符匹配零個或多個字符。像「data?.dat」這樣的匹配模式將能夠匹配查找到下列文件名:vim
data1.datapi
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}」是單目後綴操做符,「|」是雙目中綴操做符,鏈接其實也是雙目中綴操做符,不過是隱含的(即隱式的,由於鏈接是三種基本語法結構中最經常使用的,因此設計爲隱式操做符最爲合理)。
2、正則表達式功能
1.
通常而言,典型的簡單搜索和替換操做,可經過直接提供與預期的搜索結果相匹配的字面文原本實現。雖然這種方法對於文本執行簡單的、靜態的搜索和替換任務可能已經足夠了,然而卻缺少足夠的靈活性和動態性。
若經過使用正則表達式,則能夠:
查找符合某一正則表達式的文本,尤爲是查找符合某一正則表達式的非固定文本,好比查找符合某一種模式(甚至長度不定)的文本。
能夠查找字符串內符合某個文本模式的文本(子字符串),而後將其提取出來以備他用。
所謂驗證文本,是指檢査文本可否徹底由正則表達式匹配,主要用來測試和保證數據文本的合法性。
例如,能夠測試輸入字符串,以查看字符串內是否出現電話號碼模式(好比0XXX-XXXXXXXX這樣的模式:必須爲0開頭,接着3位數字、短橫槓、8位數字)。
可使用正則表達式所表示的文本模式來識別、匹配文檔中符合該文本模式的全部文本(即符合該文本模式的文本的集合),而不僅是識別、匹配某個特定的、確切的文本(好比0XXX-XXXXXXXX就是電話號碼模式,而0755-88888888就是某個特定的、確切的電話號碼),而後能夠徹底刪除匹配該文本模式的全部文本(至關於用空字符串替換)或者用其餘文本逐一進行替換。
切分也是正則表達式的常見操做之一,切分操做通常以正則表達式匹配的文本做爲間隔,將字符串切分紅多個片斷(即子字符串)。
2.
顯然,經過使用文本模式,正則表達式相比較於直接使用固定的、明確的字面文本進行簡單的、靜態的搜索和替換,更爲靈活,也更具備動態適應性。並且,正則表達式一樣也可使用字面文本進行簡單的、靜態的搜索和替換(固然,這有點大材小用了,效率也比直接搜索和替換更低,所以,字面文本的直接搜索和替換,不推薦使用正則表達式)。
所以,正則表達式的熟練運用,是文本處理人員,尤爲是編程人員的必備技能。其強大的功能、快捷的速度,一旦掌握,你將會既歎服於心,又享受其中。
3、正則表達式簡史
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
4、正則表達式流派
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對好比下:
注1:vim中的\?和\=都表示匹配0或1個前面的子表達式,但\?不能在反向查找的「?」命令中使用。
注2:vim中的右花括號}以前能夠不加反斜槓,也能夠加反斜槓,好比:\{n,m\}。
注3:PCRE中經常使用\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:
PHP:
.Net(C#、VB):
Java:
Regular Expressions Tutorials(英文)
JavaScript:
EMCAScript:RegExp (Regular Expression) Objects(英文)
Python2.7:
Regular expression operations(英文)
Python3.4:
Regular expression operations(英文)
Ruby:
Vim:
模式及查找命令 For Vim version 7.4(中文)
Search commands and patterns For Vim version 7.3(英文)
GNU Grep:
GNU Sed:
GNU awk:
二)書籍
《精通正則表達式》英文版及中文版 做者:Jeffrey E·F·Friedl 譯者:餘晟 電子工業出版社 2012-07
《正則指引》做者:餘晟 電子工業出版社 2012-05
《正則表達式必知必會》做者:Ben Forta譯者:楊濤 人民郵電出版社2015-01
《冒號課堂:編程範式與OOP思想》做者:鄭暉 電子工業出版社 2009-10
三)其餘
本系列文章還參考了網上的大量資料,除了少部分資料因爲未做大量修改(但基本上也有少許修改,由於網上文章隨意性較大,不少明顯的筆誤或先後矛盾之處,如若不改反而讓人迷糊)而標明瞭原做者和出處以外,其他因爲基本上已按本身的理解做了大量改寫,所以沒有再一一予以說明,在此對原文做者表示歉意並感謝。
另外,文中圖片小部分來自網絡,大部分爲本人制做,也再也不一一說明,在此對原圖做者表示歉意並感謝。
(未完待續)
本系列文章上一篇爲:刨根究底正則表達式之零——前言
【預告:本系列文章下一篇爲正則表達式基礎與八大原則簡介,敬請關注!】