天天看點

關于正則的迷思故事從頭開始講故事繼續PHP中的正則Go中的正則

正則是我們日常程式設計中一定會使用到的,不管是各種語言中的正則比對,還是linux/unix系統上的grep/egrep指令,都是在使用正則來比對字元串。随着用的深入,可能會感到越來越迷惑:

-- 比如php的preg系列和ereg系列

-- 比如unix的grep指令和perl語言的grep

正規表達式(regular expression)從1956年就開始出現這個概念,後來unix之父ken tompson将這個概念引入unix,出現了grep工具。但是随着unix的版本不斷演化,unix的差異也越來越大,一統江湖的posix标準就此出現。posix(portable operating system interface for unix)提供的是統一的unix接口,當然也把正則這塊統一了。于是出現了posix的兩種标準:posix basic regular expressions (bre)和posix extended regular expressions(ere)。

bre就是現在unix系統使用的grep指令,ere就是現在unix系統使用的egrep指令。ere就是bre的擴充包的意思,基本文法都是一樣的,但是兩者還是有一些差別,比如對于一些特殊符号,“{ }”是否需要使用反斜杆:

要比對“tt”,在bre中使用“t\{1,2\}”,在ere中則是使用“t{1,2}”

關于正則的迷思故事從頭開始講故事繼續PHP中的正則Go中的正則

ps:現在網絡上說的正則,如果沒有特殊說明,應該都是指的是ere。它也是現在使用最廣的正則了。

ps2:grep -e就和egrep是一樣的。

如果世界上的正則隻有一種标準,那一切看起來都這麼完美,但是在計算機世界總是有各種各樣的曆史問題。

有很多種語言也自己定義了一套正則标準,雖然大體上和posix的這套很像,但總還是有一些不同的細節的。比如perl,python,tcl(tool command language)。都有自己定義的一套正則标準。其中perl的正則到現在演化成為pcre(perl compatible regular expressions)。這個正則文法也是被php所采用的。

gnu grep,linux機器上使用最廣泛的正則文法,幾乎所有的linux機器上的grep指令都是gnu grep。它和posix是一緻的,有gnu basic regular expressions 和gnu extends regular expressions。

php中有兩套正則函數集:preg和ereg (如果你算上mb_ereg那就有三套)

preg和ereg分别代表的是pcre regular expression和posix extension regular expression。preg和ereg有一些不同,最大的不同就是preg有“分隔符”(一般是\或者|)來将正規表達式劃出來。還有就是preg是沒有大小寫不同的函數的,它使用“模式修飾符”來對大小寫進行比對。下面是摘自php文檔的函數對照表:

關于正則的迷思故事從頭開始講故事繼續PHP中的正則Go中的正則

文檔中提到的一個例子需要注意下的:

one(self)?(selfsufficient)? 比對字元串“oneselfsufficient ” 在ereg是會比對出oneselfsufficient的,但是在preg是比對到oneself的。就是說posix會盡可能的比對正則,而對于這種可“多種”比對的正則,pcre的選擇更為保守。

go中的正則包是regexp,它使用的是叫做re2(https://code.google.com/p/re2/wiki/syntax)這個c++寫的庫,這個庫支援了兩種标準:perl 和 posix

在函數中也有展現

mustcompile

mustcompileposix

是以呢,下面這個代碼:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

<code>package main</code>

<code>import(</code>

<code>    </code><code>"regexp"</code>

<code>    </code><code>"fmt"</code>

<code>)</code>

<code>func main() {</code>

<code>    </code><code>var</code> <code>origin1 = `tt`</code>

<code>    </code><code>var</code> <code>reg = `t\z`</code>

<code>    </code><code>matches1 := regexp.mustcompile(reg).findstring(origin1)</code>

<code>    </code><code>fmt.println(matches1)</code>

<code>/*</code>

<code>    </code><code>matches2 := regexp.mustcompileposix(reg).findstring(origin1)</code>

<code>    </code><code>fmt.println(matches2)</code>

<code>*/</code>

<code>}</code>

\z是隻在perl的正則文法存在,表示以t為結尾,在posix中沒有,是以如果你把注釋的部分放開,這個程式就會抛出panic