Linux/Unix工具與正則表示式的POSIX規範
對正則表示式有基本瞭解的讀者,一定不會陌生『\d』、『[a-z]+』之類的表示式,前者匹配一個數字字元,後者匹配一個以上的小寫英文字母。但是如果你用過vi、grep、awk、sed之類Linux/Unix下的工具或許會發現,這些工具雖然支援正則表示式,語法卻很不一樣,照通常習慣的辦法寫的『\d』、『[a-z]+』之類的正則表示式,往往不是無法識別就是匹配錯誤。而且,這些工具自身之間也存在差異,同樣的結構,有時需要轉義有時不需要轉義。這,究竟是為什麼呢?
原因在於,Unix/Linux下的工具大多采用POSIX規範,同時,POSIX規範又可分為兩種流派(flavor)。所以,首先有必要了解一下POSIX規範。
POSIX規範
常見的正則表示式記法,其實都源於Perl,實際上,正則表示式從Perl衍生出一個顯赫的流派,叫做PCRE(Perl Compatible Regular Expression),『\d』、『\w』、『\s』之類的記法,就是這個流派的特徵。但是在PCRE之外,正則表示式還有其它流派,比如下面要介紹的POSIX規範的正則表示式。
POSIX的全稱是Portable Operating System Interface for uniX,它由一系列規範構成,定義了UNIX作業系統應當支援的功能,所以“POSIX規範的正則表示式”其實只是“關於正則表示式的POSIX規範”,它定義了BRE(Basic Regular Expression,基本型正則表示式)和ERE(Extended Regular Express,擴充套件型正則表示式)兩大流派。在相容POSIX的UNIX系統上,grep和egrep之類的工具都遵循POSIX規範,一些資料庫系統中的正則表示式也符合POSIX規範。
BRE
在Linux/Unix常用工具中,grep、vi、sed都屬於BRE這一派,它的語法看起來比較奇怪,元字元『(』、『)』、『{』、『}』必須轉義之後才具有特殊含義,所以正則表示式『(a)b』只能匹配字串 (a)b而不是字串ab;正則表示式『a{1,2}』只能匹配字串a{1,2},正則表示式『a\{1,2\}』才能匹配字串a或者aa。
之所以這麼麻煩,是因為這些工具的誕生時間很早,正則表示式的許多功能卻是逐步發展演化出來的,之前這些元字元可能並沒有特殊的含義;為保證向後相容,就只能使用轉義。而且有些功能甚至根本就不支援,比如BRE就不支援『+』和『?』量詞,也不支援多選結構『(…|…)』和反向引用『\1』、『\2』…。
不過今天,純粹的BRE已經很少見了,畢竟大家已經認為正則表示式“理所應當”支援多選結構和反向引用等功能,沒有確實太不方便。所以雖然vi屬於BRE流派,但提供了這些功能。GNU也對BRE做了擴充套件,支援『+』、『?』、『|』,只是使用時必須寫成『\+』、『\?』、『\|』,而且也支援『\1』、『\2』之類反向引用。這樣,GNU的grep等工具雖然名義上屬於BRE流,但更確切的名稱是GNU BRE。
ERE
在Linux/Unix常用工具中,egrep、awk則屬於ERE這一派,。雖然BRE名為“基本”而ERE名為“擴充套件”,但ERE並不要求相容BRE的語法,而是自成一體。因此其中的元字元不用轉義(在元字元之前新增反斜線會取消其特殊含義),所以『(ab|cd)』就可以匹配字串ab或者cd,量詞『+』、『?』、『{n,m}』可以直接使用。ERE並沒有明確規定支援反向引用,但是不少工具都支援『\1』、『\2』之類的反向引用。
GNU出品的egrep等工具就屬於ERE流(更準確的名字是GNU ERE),但因為GNU已經對BRE做了不少擴充套件,所謂的GNU ERE其實只是個說法而已,它有的功能GNU BRE都有了,只是元字元不需要轉義而已。
下面的表格簡要說明了幾種POSIX流派的區別[1](其實,現在的BRE和ERE在功能上並沒有什麼區別,主要的差異是在元字元的轉義上)。
幾種POSIX流派的說明
流派 |
說明 |
工具 |
BRE |
(、)、{、}都必須轉義使用,不支援+、?、| |
grep、sed、vi(但vi支援這些多選結構和反向引用) |
GNU BRE |
(、)、{、}、+、?、|都必須轉義使用 |
GNU grep、GNU sed |
ERE |
元字元不必轉義,+、?、(、)、{、}、|可以直接使用,\1、\2的支援不確定 |
egrep、awk |
GNU ERE |
元字元不必轉義,+、?、(、)、{、}、|可以直接使用,支援\1、\2 |
grep –E、GNU awk |
為了方便查閱,下面再用一張表格列出基本的正則功能在常用工具中的表示法,其中的工具GNU的版本為準。
常用Linux/Unix工具中的表示法
PCRE記法 |
vi/vim |
grep |
awk |
sed |
* |
* |
* |
* |
* |
+ |
\+ |
\+ |
+ |
\+ |
? |
\= |
\? |
? |
\? |
{m,n} |
\{m,n} |
\{m,n\} |
{m,n} |
\{m,n\} |
\b * |
\< \> |
\< \> |
\< \> |
\y \< \> |
(…|…) |
\(…\|…\) |
\(…\|…\) |
(…|…) |
(…|…) |
(…) |
\(…\) |
\(…\) |
(…) |
(…) |
\1 \2 |
\1 \2 |
\1 \2 |
不支援 |
\1 \2 |
注:PCRE中常用\b來表示“單詞的起始或結束位置”,但Linux/Unix的工具中,通常用\<來匹配“單詞的起始位置”,用\>來匹配“單詞的結束位置”,sed中的\y可以同時匹配這兩個位置。
POSIX字元組
在某些文件中,你還會發現類似『[:digit:]』、『[:lower:]』之類的表示法,它們看起來不難理解(digit就是“數字”,lower就是“小寫”),但又很奇怪,這就是POSIX字元組。不僅在Linux/Unix的常見工具中,甚至一些變成語言中都出現了這些字元組,為避免困惑,這裡有必要簡要介紹它們。
在POSIX規範中,『[a-z]』、『[aeiou]』之類的記法仍然是合法的,其意義與PCRE中的字元組也沒有區別,只是這類記法的準確名稱是POSIX方括號表示式(bracket expression),它主要用在Unix/Linux系統中。POSIX方括號表示法與PCRE字元組的最主要差別在於:POSIX字元組中,反斜線\不是用來轉義的。所以POSIX方括號表示法『[\d]』只能匹配\和d兩個字元,而不是『[0-9]』對應的數字字元。
為了解決字元組中特殊意義字元的轉義問題,POSIX方括號表示法規定,如果要在字元組中表達字元](而不是作為字元組的結束標記),應當讓它緊跟在字元組的開方括號之後,所以POSIX中,正則表示式『[]a]』能匹配的字元就是]和a;如果要在POSIX方括號表示法中表達字元-(而不是範圍表示法),必須將它緊挨在閉方括號]之前,所以『[a-]』能匹配的字元就是a和-。
POSIX規範也定義了POSIX字元組,它近似等價于于PCRE的字元組簡記法,用一個有直觀意義的名字來表示某一組字元,比如digit表示“數字字元”,alpha表示“字母字元”。
不過,POSIX中還有一個值得注意的概念:locale(通常翻譯為“語言環境”)。它是一組與語言和文化相關的設定,包括日期格式、貨幣幣值、字元編碼等等。POSIX字元組的意義會根據locale的變化而變化,下面的表格介紹了常見的POSIX字元組在ASCII語言環境與Unicode語言環境下的意義,供大家參考。
POSIX字元組
POSIX字元組 |
說明 |
ASCII語言環境 |
Unicode語言環境 |
[:alnum:]* |
字母字元和數字字元 |
[a-zA-Z0-9] |
[\p{L&}\p{Nd}] |
[:alpha:] |
字母 |
[a-zA-Z] |
\p{L&} |
[:ascii:] |
ASCII字元 |
[\x00-\x7F] |
\p{InBasicLatin} |
[:blank:] |
空格字元和製表符 |
[ \t] |
[\p{Zs}\t] |
[:cntrl:] |
控制字元 |
[\x00-\x1F\x7F] |
\p{Cc} |
[:digit:] |
數字字元 |
[0-9] |
\p{Nd} |
[:graph:] |
空白字元之外的字元 |
[\x21-\x7E] |
[^\p{Z}\p{C}] |
[:lower:] |
小寫字母字元 |
[a-z] |
\p{Ll} |
[:print:] |
類似[:graph:],但包括空白字元 |
[\x20-\x7E] |
\P{C} |
[:punct:] |
標點符號 |
[][!"#$%&'()*+,./:;<=>[email protected]\^_`{|}~-] |
[\p{P}\p{S}] |
[:space:] |
空白字元 |
[ \t\r\n\v\f] |
[\p{Z}\t\r\n\v\f] |
[:upper:] |
大寫字母字元 |
[A-Z] |
\p{Lu} |
[:word:]* |
字母字元 |
[A-Za-z0-9_] |
[\p{L}\p{N}\p{Pc}] |
[:xdigit:] |
十六進位制字元 |
[A-Fa-f0-9] |
[A-Fa-f0-9] |
注1:標記*的字元組簡記法並不是POSIX規範中的,但使用很多,一般語言中都提供,文件中也會出現。
注2:對應的Unicode屬性請參考本系列文章已經刊發過的關於Unicode的部分。
POSIX字元組的使用有所不同。主要區別在於,PCRE字元組簡記法可以脫離方括號直接出現,而POSIX字元組必須出現在方括號內,所以同樣是匹配數字字元,單獨出現時,PCRE中可以直接寫『\d』,而POSIX字元組就必須寫成『[[:digit:]]』。
Linux/Unix下的工具中,一般都可以直接使用POSIX字元組,而PCRE的字元組簡記法『\w』、『\d』等則大多不支援,所以如果你看到『[[:space:]]』而不是『\s』,一定不要感到奇怪。
不過,在常用的程式語言中,Java、PHP、Ruby也支援使用POSIX字元組。其中Java和PHP中的POSIX字元組都是按照ASCII語言環境進行匹配;Ruby的情況則要複雜一點,Ruby 1.8按照ASCII語言環境進行匹配,而且不支援『[:word:]』和『[:alnum:]』,Ruby 1.9按照Unicode語言環境進行匹配,同時支援『[:word:]』和『[:alnum:]』。
說明:關於正則表示式的系列文章到此即告一段落,作者最近已經完成了一本關於正則表示式的書籍,其中更詳細也更全面地講解了正則表示式使用中的各種問題。該書暫定名《正則導引》,預計近期上市,有興趣的讀者敬請關注。
關於作者
餘晟,程式設計師,曾任抓蝦網高階顧問,現就職於盛大創新院,感興趣的方向包括搜尋和分散式演算法等。翻譯愛好者,譯有《精通正則表示式》(第三版)和《技術領導之路》,目前正在寫作《正則表示式傻瓜書》(暫定名),希望為國內開發同行貢獻一本實用的正則表示式教程。
相關推薦
Linux/Unix工具與正則表示式的POSIX規範
對正則表示式有基本瞭解的讀者,一定不會陌生『\d』、『[a-z]+』之類的表示式,前者匹配一個數字字元,後者匹配一個以上的小寫英文字母。但是如果你用過vi、grep、awk、sed之類Linux/Unix下的工具或許會發現,這些工具雖然支援正則表示式,語法卻很不一樣,照通
linux(ubuntu)文字處理工具及正則表示式
grep egrep(文字過濾) fgrep(不支援正則) 格式 grep [選項] 模式 檔案 選項:--color 指定顏色 -v反向匹配,顯示不能被模式匹配到的行 &n
Linux grep基本用法與正則表示式
本文只是對於常用的grep配合正則表示式基本用法進行簡單小結,如果想仔細的學習正則表示式,請訪問鳥哥Linux私房菜,臺灣同胞的網站是繁體中文的,需要點兒耐心。 1、grep命令 功能:輸入檔案的每一行中查詢字串。 基本用法: grep [-ac
Linux 萬用字元 與 正則表示式 的區別與詳解
背景:在linux使用過程中,經常需要查詢檔案,對命令中的萬用字元 pattern 和正則表示式的區分不是很清楚。有必要好好研究一下。 1 掃盲 1.1 萬用字元和正則表示式 當在使用命令列時,有很多時間都用來查詢你所需要的檔案,如 ls find 等。 Sh
Linux Shell的萬用字元與正則表示式
Overview wildcard是由shell處理的, 它只會出現在 command的argument 裡——既不用在 command_name裡, 也不用在 options 上。當在argument中碰到Wildcard時,shell會將其當作路徑或檔名去在磁碟上搜尋可能
sed工具與正則表達式的使用(shell第四天)
sed工具正則表達式sed工具 【流式編輯器】 —— 非交互,基於模式匹配過濾及修改文本—— 逐行處理,並將結果輸出到屏幕——可實現對文本的輸出,刪除,替換,復制,剪切,導入,導出等各種操作 命令格式:1)前置命令 | sed [選項] ‘條件指令‘ 【利用管道】2)sed [選項] ‘條件指
【前端】JavaScript與正則表示式
一、正則表示式(regular expression簡稱res) 1、定義 一個正則表示式就是由普通字元以及特殊字元(稱為元字元)組成的文字模式。該模式描述在查詢文字主體時待匹配的一個或多個字串。正則表示式作為一個模板,將某個字元模式與所搜尋的字串進行匹配。 2、作用 正則表示式
jmeter設定全域性變數與正則表示式提取器
介面測試中,很多介面都要帶上登入後的token才能正常傳送請求,這裡記錄一下登入獲取token設定為全域性變數供其他介面使用 登入後返回資訊資訊中會有一個token值,新增後置處理器中的正則表示式提取token,然後用後置處理器中的BeanShell PostProcessor設定token為全域性變數
Python學習筆記模式匹配與正則表示式之使用和不使用正則表示式
隨筆記錄方便自己和同路人查閱。 #------------------------------------------------我是可恥的分割線------------------------------------------- 假設你希望在字串中查詢電話號碼。你知道模式:3個數字,一
正則表示式——POSIX字元組
前面介紹了常用的字元組,但是在某些文件中,你可能會發現類似[:digit:]、[:lower:]之類的字元組,看起來不難理解(digit就是"數字",lower就是"小寫"),但又很奇怪,它們就是POSIX字元組(POSIX Character Class)。因為某些語言的文件中出現了這些字元組,為避免困惑,
Day004_Linux基礎命令之特殊符號與正則表示式萬用字元
特殊符號: . 點 cd . 表示當前目錄 ' '' 單引號,所見即所得 原封不動輸出 " ""雙引號,裡面的特殊符號會被解析執行 `` ====$( ) 先執行() 裡的命令,把結果留下 > 重定向符號 先清空檔案內容, 再追加檔案最後一行 &
LINUX學習—grep和正則表示式(LINUX三劍客)
grep, egrep, fgrep grep(GLOBAL RESEARCH) 是一種強大的文字搜尋工具,它能使用正則表示式搜尋文字,並把匹配的行打印出來。根據模式,搜尋文字,並將符合模式的文字行顯示出來。只能使用基本正則表示式 要使用擴充套件正則表示式需要-E pattern
Javascript 與正則表示式
Javascript 與正則表示式 一、正則表示式(regular expression簡稱res) 1、定義: 一個正則表示式就是由普通字元以及特殊字元(稱為元字元)組成的文字模式。該模式描述在查詢文字主體時待匹配的一個或多個字串。正則表示式作為一個模板,將某個字
Groovy入門-字串處理與正則表示式
字串處理-1 println ‘lxt008 said "Groovy"' println "lxt008 said 'Grails'" def str1 = 'Groovy&Grails&lxt008' println str1[4]
Python爬蟲與正則表示式
Python爬蟲與正則表示式 一.Python中萬用字元的使用 1.表示方式 表示 意義 * 匹配0到任意字元 ? 匹配單個字元
Scala的檔案讀寫操作與正則表示式
在本篇部落格中你將會學習並瞭解常用的檔案處理任務,例如讀取檔案的一行文字,本部落格的要點包含: Source.fromFile(...).getLines.toArray 輸出檔案所有行 Source.fromFile(...).mkString 以字串形式輸出檔案內容 將字串轉換為數字,可以使用toI
Scala的檔案讀寫與正則表示式
在本篇部落格中你將會學習並瞭解常用的檔案處理任務,例如讀取檔案的一行文字,本部落格的要點包含: 1. Source.fromFile(…).getLines.toArray 輸出檔案所有行 2. S
Hbulder安裝與正則表示式初識一
Hbulider的安裝 Hbulider主要用來編寫html檔案,正則表示式寫在js頁面中, 用此工具對學習正則表示式有很大的幫助 Hbulider的下載網址為http://www.dcloud.
JavaWEB04 JavaScript與正則表示式
Javascript 與正則表示式 一、正則表示式(regular expression簡稱res) 1、定義: 一個正則表示式就是由普通字元以及特殊字元(稱為元字元)組成的文字模式。該模式描述在查詢文字主體時待匹配的一個或多個字串。正則表示式作為一個模板,將某個字
elasticsearch-wildcard、regexp萬用字元與正則表示式查詢
萬用字元與正則表示式查詢 假設將郵編作為 not_analyzed 的精確值欄位索引,所以可以為其建立索引,如下: PUT /my_index { "mappings": { "address": { "properties