然後, 我這裡才跟你講:
--- RE 表達式裡的字符也是分為 meta 與 literal 這兩種!
呵, 不知親愛的讀者是否被我搞混亂了呢? ... ^_^
這也難怪啦, 因為這的確是最容易混亂的地方, 剛學 RE 的朋友很多時候都死在這裡!
因此請特別小心理解哦...
簡單而言, 除非你將 RE 寫在特定程式使用的腳本裡,
否則, 我們的 RE 也是透過 command line 輸入的.
然而, 不少 RE 所始用的 meta 字符, 跟 shell meta 字符是衝突的.
比方說, * 這個字符, 在 RE 裡是一個 modifier(後述), 在 command line 上, 卻是個 wildcard !
那麼, 我們該如何解決這樣的衝突呢? 關鍵就是看你對十三問第 4 問所提的 quoting 是否夠理解了!
若你明白到 shell quoting 就是在 command line 上關閉 shell meta 這一基本原理,
那你就能很輕鬆的解決 RE meta 與 shell meta 的衝突問題了:
--- 用 shell quoting 關掉 shell meta 就是了!
就這麼簡單... ^_^
再以剛提到的 * 字符為例, 若在 command line 中沒有 quoting 處理的話, 如 abc* ,
那就會被作為 wildcard expansion 來擴充及重組了.
若將之置於 quoting 中, 如 "abc*", 則可避免 wildcard expansion 的處理.
尤其在 command line 的位置裡, wildcard 只作用於 argument 的 path 上.
但是 RE 卻只用於"字串處理"的程式之中, 這與路逕名稱一點關系也沒有!
RE 所處理的字串通常是指純文檔或透過 stdin 讀進的內容...
在RE的表达式里,主要分两种字符(character):literal 与 meta。
literal:就是在RE里不具特殊功能的字符,如 abc,123 这些;
meta在RE里具有特殊的功能,要开关之,需要在meta 前面使用 escape(\)字符。
字符组合(character set)就是将多个连续的字符作一个集合,比方说:
abc:表示abc三个连续的字符,但批次独立而非集合。(可简单视为三个char. set)
(abc):表示abc这三个连续字符的集合。(可简单视为一个char. set)
abc|xyz:表示或abc或xyz这两个char set之一。
[abc]:表示单一字符,可为a或b或c。(与wildcard值[abc]原理相同)
[^abc]:表示单一字符,不为a或b或c即可。(与wildcard之[!abc]原理相同)
[]abc]:表示单一字符,可为]或a或b或c。]必须放第一个。
[abc-]:表示单一字符,可为a或b或c或-。-必须放在最后一个。
[a^bc]:表示单一字符,可为a或^或b或c。^不能放在第一个。
.:表示任意单一字符。(与wildcard之?原理相同)
RE中常见的meta字符:
——锚点(anchor)
用以标识RE于句子中的位置所在。常见有:
^:表示句首。如^abc表示以abc開首的句子。(以换行符为标记)
$:表示句尾。如abc$表示以abc结尾的句子。(以换行符为标记)
\<:表示词首。如\<abc表示以abc開首的词。
\>:表示词尾。如abc\>表示abc结尾的词。
——修饰字符(modifier)
独立表示时本身不具意义,专门用以修改前一个char. set的出现次数。常见的有:
*:表示前一个char. set 的出现次数为0或多次。如ab*c表示a与c之间可有0或多个b存在。
?:表示前一个char. set的出现次数为0或1次。如ab?c表示a与c之间可有0或1个b存在。
+:表示前一个char. set 的出现次数为1或多次。如ab+c表示a与c之间可有1或多个b存在。
{n}:表示前一个char. set 的出现次数必须为n次。如ab{3}c表示a与c之间必须有3个b存在。
{n,}:表示前一个char. set 的出现次数至少为n次。如ab{3,}c表示a与c之间至少有3个b存在。
{n,m}:表示前一个char. set 的出现次数为n到m次。如ab{3,5}c表示a与c之间有3到5个b存在。
然而, 當我們在識別 modifier 時, 卻很容易忽略"邊界(boundary)"字符的重要性.
以剛提到的 ab{3,5}c 為例, 這裡的 a 與 c 就是邊界字符了.
若沒有邊界字符的幫忙, 我們很容以作出錯誤的解讀.
比方說: 我們用 ab{3,5} 這個 RE (少了 c 這個邊界字符)可以抓到 abbbbbbbbbbc (a 後有 10 個 b )這串字嗎?
從剛才的 modifier 我們一般會認為我們要的 b 是 3 到 5 個, 若超出了此範圍, 就不是我們要表達的.
因此, 我們或會很輕率的認為這個 RE 抓不到結果(上述“abbbbbbbbbbc”字串)...
然而答案卻是可以的! 為甚麼呢?
讓我們重新解讀 ab{3,5} 這個 RE 看看:
我們要表達的是 a 後接 3 到 5 個 b 即可, 但 3 到 5 個 b 後面我們卻沒規定是甚麼,
因此在 RE 後面可以是任意的文字, 當然包括 b 也可以啦! (明白了嗎?)
同樣的, 我們用 b{3,5}c 也同樣可以抓到 abbbbbbbbbbc 這串字的.
但我們若使用 ab{3,5}c 這樣的 RE 時, 由於同時有 a 與 c 這兩個邊界字符, 那就截然不同了!
比方以 grep 來說, 在 Linux 上你可找到 grep, egrep, fgrep 這幾個程式, 其差異大致如下:
* grep:
傳統的 grep 程式, 在沒有參數的情況下, 只輸出符合 RE 字串之句子. 常見參數如下:
-v: 逆反模示, 只輸出"不含" RE 字串之句子.
-r: 遞迴模式, 可同時處理所有層級子目錄裡的文件.
-q: 靜默模式, 不輸出任何結果(stderr 除外. 常用以獲取 return value, 符合為 true, 否則為 false .)
-i: 忽略大小寫.
-w: 整詞比對, 類似 \<word\> .
-n: 同時輸出行號.
-c: 只輸出符合比對的行數.
-l: 只輸出符合比對的文件名稱.
-h:查询多文件时 不显示文件名。
-s:不显示不存在或无匹配文件的错误信息。
-v:显示不包含匹配文件的所有行。
-o: 只輸出符合 RE 的字串. (gnu 新版獨有, 不見得所有版本都支持.)
-E: 切換為 egrep .
* egrep:
為 grep 的擴充版本, 改良了許多傳統 grep 不能或不便的操作. 比方說:
- grep 之下不支持 ? 與 + 這兩種 modifier, 但 egrep 則可.
- grep 不支持 a|b 或 (abc|xyz) 這類"或一"比對, 但 egrep 則可.
- grep 在處理 {n,m} 時, 需用 \{ 與 \} 處理, 但 egrep 則不需.
egrep的一个显著特性是可以以一个文件作为保存的字符串,然后降至传给egrep作为参数,为此使用-f开关。
諸如此類的... 我個人會建議能用 egrep 就不用 grep 啦... ^_^
* fgrep:
不作 RE 處理, 表達式僅作一般字串處理, 所有 meta 均失去功能.
grep一般格式为:
grep [选项]基本正则表达式[文件]
这里基本正则表达式可为字符串。
单引号双引号
在grep命令中输入字符串参数时,最好将其用双引号括起来。
在调用模式匹配时,应使用单引号。
1、类名
grep允许使用国际字符模式匹配或匹配模式的类名形式。
类名及其等价的正则表达式类
[[:upper:]] [A-Z]
[[:alnum:]] [0-9a-zA-Z]
[[:lower:]] [a-z]
[[:space:]] 空格或tab键
[[:digit:]] [0-9]
[[:alpha:]] [a-zA-Z]