
作者:kamly,騰訊 CDC 應用開(kāi)發(fā)工程師
正則表達式在我們日常的軟件開(kāi)發(fā)過(guò)程中被廣泛使用,例如編寫(xiě) Nginx 配置文件、在 Linux 與 macOS 下查找文件,然而不同軟件不同操作系統對于正則的應用有著(zhù)不一樣的行為,主要原因是正則表達式演進(jìn)過(guò)程中,出現 POSIX 與 PCRE 派系之分。
先了解一下正則表達式的演進(jìn)史。
20 世紀 40 年代,兩位神經(jīng)生理學(xué)家 Warren McCulloch 和 Walter Pitts,研究出了一種用數學(xué)方式來(lái)描述神經(jīng)網(wǎng)絡(luò )的方法,可以將神經(jīng)系統中的神經(jīng)元描述成小而簡(jiǎn)單的自動(dòng)控制元。
50 年代,一位叫 Stephen Kleene 的數學(xué)家在 McCulloch 和 Pitts 早期工作的基礎上,發(fā)表了《神經(jīng)網(wǎng)絡(luò )事件表示法和有窮自動(dòng)機》 論文。這篇論文描述了一種叫做 "正則集合(Regular Sets)" 的數學(xué)符號,引入了正則表達式的概念。
60 年代,Unix 之父 Ken Thompson 發(fā)表了 《正則表達式搜索算法》 論文。并且根據這篇論文的算法,將正則引入到編輯器 qed ,以及之后的編輯器 ed 中,然后又移植到了我們熟悉的文本搜索工具 grep 中。
70 年代,由于 grep 支持的功能不多,因此 Alfred Aho 編寫(xiě)了 egrep 程序(其中 e 表示加強版的意思)。在 grep 、 egrep 發(fā)展的同時(shí), awk 、 lex 、 sed 等異軍也開(kāi)始凸起,每個(gè)程序所支持的正則表達式都有差別。
80 年代,POSIX (Portable Operating System Interface) 標準公諸于世,它制定了不同的操作系統都需要遵守的一套規則,其中就包括正則表達式的規則。遵循 POSIX 規則的正則表達式,稱(chēng)為 POSIX 派系的正則表達式。Unix 系統或類(lèi) Unix 系統上的大部分工具,如 grep 、sed 、awk 等都屬于 POSIX 派系。同樣在 80 年代,Larry Wall 發(fā)布了 Perl 編程語(yǔ)言,其中引入的正則表達式功能是顆耀眼明珠。
90 年代,隨著(zhù) Perl 語(yǔ)言的發(fā)展,它的正則表達式功能越來(lái)越強悍。為了把 Perl 語(yǔ)言中正則的功能移植到其他語(yǔ)言中, PCRE (Perl Compatible Regular Expressions)派系的正則表達式也誕生了?,F代編程語(yǔ)言如 Python , Ruby , PHP , C / C++ , Java 等正則表達式,大部分都屬于 PCRE 派系。
總的來(lái)說(shuō),經(jīng)歷 20 世紀 80 至 90 年代洗禮,正則表達式形成了兩大派系:POSIX 與 PCRE:

POSIX 派系 與 PCRE 派系具體有什么不一樣?我們應該何時(shí)選擇哪個(gè)派系?
POSIX 派系是遵循 POSIX 規則的正則表達式,其中代表軟件有:grep ,sed 和 awk 等。
POSIX 派系分為兩種標準:
BRE 標準(Basic Regular Expression 基本正則表達式)
ERE 標準(Extended Regular Expression 擴展正則表達式)
在 GNU 版本下,兩者具體差別如下:

是不是很難找到兩者的差別點(diǎn)呢?仔細留意一下,第 3,4,5,7 行的內容。我們能發(fā)現,如果使用 BRE 標準,需要對 [], (), | 符號進(jìn)行轉義。作者看來(lái) ERE 實(shí)際上是 BRE 的一個(gè)擴展標準,開(kāi)發(fā)者使用 ERE 能書(shū)寫(xiě)更簡(jiǎn)單的正則表達式,不需要對某些字符進(jìn)行特殊轉義。
POSIX 派系有自己的字符組,叫 POSIX 字符組,具體解釋如下所示:

篇幅原因,僅提供部分需要關(guān)注的對比,具體看【附錄-POSIX 字符組詳細內容】。
現代編程語(yǔ)言大部分都屬于 PCRE 派系,如 Python , PHP 和 Java 等。
Perl1 提供了正則表達式操作符——是通用腳本語(yǔ)言的首創(chuàng );
Perl2 補充 /i 量詞,能夠進(jìn)行不區分大小寫(xiě)匹配等;
Perl3 支持 /e 量詞,能夠增強替換運算符的能力;{min,max} 區間量詞等;
Perl5 添加 非捕獲的括號,忽略?xún)?yōu)先的量詞,順序環(huán)視功能等。
隨著(zhù) Perl 每次迭代,新增的特性使正則表達式本身逐漸成為一門(mén)強大的編程語(yǔ)言,并為其提供了進(jìn)一步發(fā)展空間,也因為派系的整合, PCRE 庫橫空出世,它是一套兼容 Perl 正則表達式庫,全面仿制 Perl 的正則表達式的語(yǔ)法和語(yǔ)義。其他開(kāi)發(fā)人員可以把 PCRE 庫整合到自己的工具和語(yǔ)言中,為使用者提供豐富的正則功能。
更易用
相對于 POSIX 派系的 BRE 標準,不需要使用 \ 進(jìn)行轉義。
例如:在多選分支結構直接使用 | 即可(1|2 表達 1 或者 2)
更簡(jiǎn)潔
在兼容 POSIX 字符組的基礎上還支持更簡(jiǎn)潔的寫(xiě)法。
例如:\w 等價(jià)于 [[:word:]],\d 等價(jià)于 [[:digit:]]
更多功能
例如:Look-around (環(huán)顧斷言), Non-capturing Group (非捕獲組), non-greedy (非貪婪)等。
正因為 PCRE 與 POSIX 相比, PCRE 使用起來(lái)更加易用簡(jiǎn)潔(不需要轉義,有更簡(jiǎn)潔字符組),功能更加豐富(非捕獲組,環(huán)顧斷言,非貪婪)。如果沒(méi)有特殊原因,應盡可能使用 PCRE 派系,讓正則匹配的結果更符合我們預期。

篇幅原因,僅提供部分需要關(guān)注的對比,具體看【附錄-PCRE、GNU BRE、GNU ERE 對比】。如果讀者對貪婪和非貪婪模式感興趣,可以了解一下正則表達式的執行引擎,或許會(huì )讓你對正則表達式產(chǎn)生新的看法。
了解完 PCRE 派系和 POSIX 派系后,我們來(lái)做個(gè)簡(jiǎn)單的測試。文本內容如下,我們目標是需要匹配其中的數字:
- 12345
- abcde
實(shí)驗環(huán)境為 Linux 與 macOS 下的 grep ,分別使用:
不帶參數,為 POSIX BRE 模式;
帶參數 -E,為 POSIX ERE 模式;
帶參數 -P,為 PCRE 模式( macOS 不支持)。

通過(guò) man grep ,可以了解到 Linux 下的 grep 默認是 POSIX BRE 模式:
- -G, --basic-regexp
- Interpret PATTERN as a basic regular expression (BRE, see below). This is the default.
加上 -E 則是 POSIX ERE 模式:
- -E, --extended-regexp
- Interpret PATTERN as an extended regular expression (ERE, see below).
加上 -P 則是 PCRE 模式:
- -P, --perl-regexp
- Interpret the pattern as a Perl-compatible regular expression (PCRE). This is experimental and grep -P may warn of unimplemented features.
從實(shí)驗結果來(lái)看, grep '\d' demo.txt' 命令在 Linux 與 macOS 輸出是不一樣的,這是因為 macOS 自帶的 grep 是 BSD 版本,而 Linux 下的 grep 則是 GNU 版本。
macOS 基于 BSD,預置 BSD 工具鏈,眾多命令行工具與 Linux 下 GNU 工具的行為不一致,例如常見(jiàn)的 gzip , find 和 sed ,以及本文重點(diǎn)提及的 grep。
讀者如果希望自己的 macOS 電腦能完美運行 GNU/Linux 上的 Shell 腳本,可以使用 homebrew 來(lái)逐一替換,例如本文提及的 grep 可以通過(guò) brew install grep 。
正則表達式以及相關(guān)生態(tài)在發(fā)展了數十年的情況下,應用場(chǎng)景已經(jīng)非常廣泛。讀者在使用軟件工具的時(shí)候,應需要了解該工具支持正則表達式何種派系,避免執行腳本遷移不同環(huán)境后運行結果不符合預期。
例如:
確認版本類(lèi)型(GNU , BSD)。建議統一使用 GNU 中 grep 程序,避免在不同環(huán)境下運行結果不符合預期的現狀
確認每個(gè)模式下的選項(BRE , ERE , PCRE)。盡可能選擇 PCRE 模式,因為 PCRE 模式更符合我們的使用習慣。
此外,除了關(guān)心正則表達式的標準之外,強烈推薦讀者細讀正則表達式的執行引擎,或許能幫助你寫(xiě)出更性能更好的正則表達式,避免因為正則表達式的地獄回溯導致的應用程序的 OOM。



BSD 是加州大學(xué)伯克利分校對 Unix 系統進(jìn)行的擴展與重新發(fā)行。目前的 BSD 生態(tài)系統圍繞三大主要操作系統:
FreeBSD、OpenBSD、NetBSD
DragonFly BSD
其他發(fā)行版
騰訊程序員視頻號最新視頻
聯(lián)系客服