天天看點

關于正則的迷思

正則是我們日常程式設計中一定會使用到的,不管是各種語言中的正則比對,還是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}”

Image

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中的正則

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

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

Image(1)

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

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

Go中的正則

在函數中也有展現

MustCompile

MustCompilePOSIX

是以呢,下面這個代碼:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

package main

import(

)

func main() {

/*

*/

}

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