原創:打碼日記(微信公眾號ID:codelogs),歡迎分享,轉載請保留出處。
簡介
對於剛使用Linux不久的同學,肯定會遇到這個問題,就是用grep匹配數字時,發現\d匹配不了數字。
主要原因是grep支持三種正則表達式BRE,ERE,PCRE,而其默認使用的是BRE,但\d是定義在PCRE中的,所以grep默認是不支持\d的。
正則表達式分類
BRE
基本的正則表達式(Basic Regular Expression 簡稱 BRE),由posix標准定義,為了統一歷史上混亂的正則實現。
ERE
擴展的正則表達式(Extended Regular Expression 簡稱 ERE),由posix標准定義,解決了一些BRE的缺陷並補充了一些新功能。
PCRE
Perl兼容的正則表達式(Perl Compatible Regular Expression 簡稱 PCRE),由perl語言發展而來,而后移植到各平台與編程語言中,所以稱其為Perl兼容的正則表達式。
如今主流編程語言(java,python)中的正則實現,基本都是PCRE,PCRE功能也比BRE,ERE要強大得多,雖然大部分同學只知道其基礎部分。
BRE,ERE,PCRE對比
| 功能 | 描述 | BRE | ERE | PCRE |
|---|---|---|---|---|
| 字符組 | 匹配指定任一字符 | [..] |
[..] |
[..] |
| 排除字符組 | 匹配非指定任一字符 | [^..] |
[^..] |
[^..] |
| 簡寫字符組.號 | 匹配非換行字符 | . |
. |
. |
| 簡寫字符組 | 匹配數字 匹配非數字 |
不支持 | 不支持 | \d \D |
| 簡寫字符組 | 匹配字母數據下划線 匹配非字母數字下划線 |
\w \W |
\w \W |
\w \W |
| 簡寫字符組 | 匹配空白符 匹配非空白符 |
\s \S |
\s \S |
\s \S |
| 匹配量詞 | 匹配0次或多次 | * |
* |
* |
| 匹配量詞 | 匹配1次或多次 | \+ |
+ |
+ |
| 匹配量詞 | 匹配0次或1次 | \? |
? |
? |
| 匹配量詞 | 匹配x次 匹配x次或以上 匹配x次或以上y次或以下 |
\{x\} \{x,\} \{x,y\} |
{x} {x,} {x,y} |
{x} {x,} {x,y} |
| 懶惰匹配量詞 | 盡量不匹配 | 不支持 | 不支持 | *? +? ?? {x}? {x,}? {x,y}? |
| 占有匹配量詞 | 匹配后就不會回溯 | 不支持 | 不支持 | *+ ++ ?+ {x}+ {x,}+ {x,y}+ |
| 位置限定 | 匹配行開頭位置 | ^ |
^ |
^ |
| 位置限定 | 匹配行結尾位置 | $ |
$ |
$ |
| 位置限定 | 匹配單詞邊界 匹配非單詞邊界 |
\b \B |
\b \B |
\b \B |
| 多選結構 | 多選匹配條件 | | |
` | ` |
| 捕獲組與反向引用 | 分組並捕獲 | \(...\) \1 \2 |
(...) \1 \2 |
(...) \1 \2 |
| 僅分組 | 僅分組不捕獲括號 | 不支持 | 不支持 | (?:) |
| 固化分組 | 匹配后就不回溯的分組 | 不支持 | 不支持 | (?>) |
| 環視 | 零長度斷言 | 不支持 | 不支持 | (?=...) (?!...) (?<=...) (?<!...) |
可以發現BRE與ERE的主要區別是,BRE對於+,?,{x},|,(),需要使用\轉義后,才能表達正則的含義,否則視為普通字符,而ERE默認表示正則元字符,加\才是普通字符。
另外,對於我們常用的\d,BRE與ERE都不支持。
命令與它們的正則分類
grep
對於grep,默認使用BRE,grep -E或egrep使用ERE,實際上grep -E與egrep是等價的,grep -P使用PCRE。
另外,值得一提的是grep -F代表普通字符串匹配,grep -w代表單詞模式匹配,如grep -w abc等價於grep '\babc\b',其中\b用於匹配單詞邊界。
sed
對於sed,默認也使用BRE,sed -E或sed -r使用ERE,sed不支持PCRE。
awk
對於awk來說,默認就是ERE,它不支持BRE與PCRE。
另外,PCRE發布了兩個新的輪子pcregrep與pcre2grep,功能上類似於grep,不過是專門用PCRE規范實現的,pcre2grep有個好用的功能,可以很方便的使用正則提取數據,如下:
$ echo -e 'name:zhangsan,age:18 \n name:lisi,age:20' | pcre2grep -O '$1 $2' 'name:(\w+),age:(\d+)'
zhangsan 18
lisi 20
往期內容
不容易自己琢磨出來的正則表達式用法
原來awk真是神器啊
Linux文本命令技巧(上)
Linux文本命令技巧(下)
字符編碼解惑
