搞編程的都知道正則表達式是什麼東西,這裏就很少囉嗦了,須要強調的是,這篇文章並非教你怎麼去使用用正則表達式,正則表達式的語法並非本文的重點,這篇文章的目的就是剝開正則表達式的語法糖,來看一看正則表達式最本質的原理,若是文章中有錯誤或者紕漏,歡迎批評指正。程序員
在上面我提到了語法糖的概念,也許有人還不清楚語法糖是什麼東西,這裏簡單的說一下。正則表達式
語法糖(Syntactic sugar),也譯爲糖衣語法,是由英國計算機科學家彼得·約翰·蘭達(Peter J. Landin)發明的一個術語,指計算機語言中添加的某種語法,這種語法對語言的功能並無影響,可是更方便程序員使用。一般來講使用語法糖可以增長程序的可讀性,從而減小程序代碼出錯的機會。——摘自 百度百科編程
能夠這麼說吧,像C、C++、Java等等這些編程語言均可以看作成語法糖,由於最終仍是得將這些高級程序語言翻譯成機器代碼,也就是10101……這樣的形式,要知道全部的可執行程序最終均可以只須要賦值和跳轉兩種結構便可,而高級語言都是對這兩種結構的封裝,來適應不一樣的應用場景,除了機器代碼,彙編和這些高級語言都是語法糖,一層一層的包裝,達到簡化開發的目的,你們想一想,若是沒有這些語法糖,那咱們豈不是得每天用機器代碼寫程序?閉包
這裏先引入一個小小的例子,我想在閱讀這篇文章的人都知道什麼是算數表達式,最基本的算數表達式:編程語言
1,2,3,4,5,6,7,8,9,0,…… +,-,*,/,……
這些都是最基本的算數表達式,而由這些最基本的算數表達式能夠構造出更加複雜的複合表達式好比1+1,3*5等等,不管是基本的仍是複合的,它們都是算數表達式,經過這個例子,來天然的過渡到下面正則表達式的內容,其實本質上算數表達式和正則表達式的道理是差很少的。學習
構成正則表達式最基本的就是給定的字符集∑={c1,c2,c3,……,cn},這就至關於算數表達式中的0,1,2,3……這些基本算數表達式。
接下來呢,就是他的概括定義,來告訴咱們如何經過最基本的字符集構造出複雜的正則表達式:翻譯
若是M,N是正則表達式,則如下也是正則表達式:code
**選擇** M|N = {M,N} **鏈接** MN = {mn | m∈M, n∈N} **閉包** M* = {ε,M,MM,MMM,……}
不難看出,以上的概括定義給出了正則表達式最基本的的形式,不管多麼複雜的正則表達式都是在這個基礎上構成的。htm
如今咱們經過一個小例子來加深對上面概念的理解:開發
給定一個字符集∑={a,b},能夠寫出那些正則表達式呢? 1. ε 2. a,b 3. ε|ε,ε| a , ε| b ,…… 4. εa , εb , ab , εε , …… 5. a(ε| a) , b(ε|b),…… 6. ε* , (a(ε| a))*,…… 7. ……
也就是說,單個的字符都是正則表達式,它們按照上面的定義組合起來依然是正則表達式,正則表達式與正則表達式相互組合又能夠生成新的正則表達式,在複雜的正則表達式都是由這些基本的正則表達式構成,固然了上面這些只是該字符集的正則表達式的一小部分,由於這個字符集的正則表達式集合是一個無限集,到這裏,我想你們應該有所體會。
咱們再來看一個例子:
咱們用上面的正則表達式的概念來構造出用來描述C語言標識符的正則表達式: 首先給定字符集,咱們都知道C語言的字符集有ASCII碼構成。 C語言標識符的格式:以字母或下劃線開頭,後面跟零個或多個字母、數字或下劃線。 該怎麼用正則表達式來描述呢? (a|b|c|……|z|A|B|C|……|Z|_)(a|b|c|……|z|A|B|C|……|Z|0|1|2|3|……|9|_))*
首先來看,這個正則表達式是由兩個子表達式鏈接而成,每一個子表達式都是用選擇符|構成,又由於第二個子表達式能夠出現零或屢次,因此加上閉包,是否是看的腦殼都大了,是否是以爲平時何時這麼寫過正則表達式,下面就得說說語法糖的做用啦。
你們接觸到的正則表達式的語法彷佛是有差別的,好比POSIX風格正則表達式和Perl風格正則表達式,要知道不管什麼風格的正則表達式它們背後的原理都是同樣的,只是在上層提供的語法糖不同而已,實際應用的過程當中都是根據上面的原理演變過來的,語法糖能夠大大簡化正則表達式的形式,變得更容易閱讀和理解,就像下面的對應關係同樣。
[c1-cn] == c1|c2|c3|……|cn e? == ε|e e+ == (e*)\ε e{i,j} == i到j個e鏈接
這裏就不一一舉例了,不管上面的對應關係中左邊的語法如何變化,它所對應的右邊的基本原理都是同樣的。
正則表達式能夠寫的很是複雜,複雜到除了做者外不多有人看的懂的,曾經我也是一度不能自拔,但隨着學習的深刻,慢慢的發現,剝開正則表達式表面的東西,去看背後的原理,纔有一種恍然大悟的感受。