1. 程式人生 > >GNU/Linux 正則表達式與三劍俠(grep,sed,awk)(精)

GNU/Linux 正則表達式與三劍俠(grep,sed,awk)(精)

重復 深入理解 不同的 原則 寬度 搜索命令 自定義 -o 排序

相關好文章推薦:

shell命令行的解析原理(單雙無引號與字符及通配符的關系):http://www.cnblogs.com/f-ck-need-u/p/7426371.html

正則表達式裏是如何表達字符集:https://www.cnblogs.com/f-ck-need-u/p/9621130.html

grep的應用:https://www.cnblogs.com/f-ck-need-u/p/7462706.html

sed的應用:https://www.cnblogs.com/f-ck-need-u/p/7499471.html


GNU 的正則表達式

傳聞中三劍俠的威名響徹雲霄,傳說中若沒有正則表達式的神功,三劍俠也是蕓蕓眾生,江湖中傳言"欲成劍俠,先練神功",不管傳說或傳聞我都信。

度度果然不是蓋的,一下就拔出了正則的歷史,不看不知道,一看就大有來頭,大約就是國外幾位猛人科學家在搞一個偉大的工程時誕生了正則數學表達式,隨後被目光深遠的Ken,將這正則表達式引入於Unix的編輯器中。後面的事情大家都很清楚了,三劍俠大鬧搜索界,傳說由此開始,而故事遠遠沒有落幕,......

從正則的歷史中,可以看出正則表達式對英文是100%的原生,也就是為英文的而生(會不會因英文而滅,不好說,或許明天你就嫁給我了,會有中文的筆畫正則也說不定,拼音正則也行),主要應用於按某規則搜索匹對英文中的內容,所以對英文的26個字母不熟悉的同誌要努力下了(俺初中英語非常6,所以這26個英文字母,蒙著眼睛也知道誰是誰,誰跟誰,一點不模糊。),那麽對英文的結構,就需要了解下,英文單詞

由英文字母排列組合並以空格來分隔每一個單詞,這個就是我們下工夫及體會的本質(英文字母,單詞[ 每個字母所在的位置決定了單詞意義 ],空格構成英語文本的三劍豪)。

對所愛,要重復大聲說:trust me , I love you

1 字符(我思故我在,能想的,都是字符)

2 字母的不同排序組合構成不同的單詞

3 空格分隔單詞(只要有某字符分隔單詞,采用什麽字符都可以)

圖解正則表達式的對英語文本的看法

技術分享圖片

示例:I love u 的字符與位置關系
字符 I 空格 l o v e 空格 u
位置 0 1 2 3 4 5
6 7 8

對英文(其他字符集)搜索的兩種模式(字符[ 組合 ]位置,字符[ 組合 ]的排序)

字符 [ 組合 ] 位置搜索方式

位置搜索方式比較單一,目的是確定字符(單詞)在整行字符排列位置上,常用^來表示字符(單詞)在一行文本的最開始位置(一行的頂格位置), $ 來表示字符(單詞)在一行文本的最末尾的位置(一行的最末尾位置),任意單字符*表示所有的位置,\b作用就是單詞與單詞之間的位置,\B作用就是某單詞內字母與字母之間的位置,這兩個大小傻B不能用說,要直接上才明白。

這裏有個知識點,就是shell的通配符及單引號、雙引號、無引號與正則表達的元字符的應用

shell 命令行輸入命令且回車 --> shell會對輸入命令及參數進行解析 (為了讓你的意圖能正確到達正則,了解shell的解析是必要的)--> 正則表達式解析工作

^、$、任意字符*

* 表示重復前一個字符(單詞)0~無限次,當等於0的情況,z*就表示位置了(其中z可以是任意的字符)。

通過sed的替換,將一句話的所有位置都替換6,替換後的位置比之前的位置又擴容了

[root@server01 ~]# echo "It‘s my life.It‘s my life." | grep --color It   
It‘s my life.Its my life.
[root@server01
~]# echo "It‘s my life.It‘s my life." | grep --color ^It It‘s my life.It‘s my life. [root@server01 ~]#
[root@server01 ~]# echo "It‘s my life.It‘s my life." | sed s/z*/6/g
6I6t6‘6s6 6m6y6 6l6i6f6e6.6I6t6‘6s6 6m6y6 6l6i6f6e6.6
[root@server01 ~]# echo "It‘s my life.It‘s my life." | sed s/^a*/6/g 6It‘s my life.It‘s my life. [root@server01 ~]#
[root@server01 ~]# echo "It‘s my life.It‘s my life." | grep --color fe\.$  
It‘s my life.It‘s my life.
[root@server01 ~]# echo "It‘s my life.It‘s my life." | sed -r s/(yf)*$/6/g
It‘s my life.It‘s my life.6
\B、\b
\B:一單詞內的字母,不含首或尾字母(組合) \b:單詞與單詞之間的分隔,以單詞的首或尾字母(組合)及非\w字符明確分隔。註意要明確是你認為的單詞
[root@server01 ~]# echo live love life ifthen thenif |grep --color \Bi\B
live love life ifthen thenif
[root@server01 ~]#
[root@server01 ~]# echo live love life left list |grep --color \bl\w\+e\b           
live love life left list
[root@server01 ~]#

常用的組合:

^$ 表示空行。第一個位置同時是開始也是結束。

[root@server01 ~]# echo live love life left list |grep --color \bl.*\+e\b
live love life left list
[root@server01 ~]# 

註意:

\bl.*\+e\b 的寫法是認為"live love life"是一個整體,可以理解為一個單詞,因為.*的意思是表示所有的字符

\bl\w\+\e\b 的寫法是認為live love life 是三個詞。

[root@server01 ~]#  echo live,love-life;left:list |grep --color \bl\w\+e\b    
live,love-life;left:list
[root@server01 ~]# 

字符 [ 組合 ] 的排序搜索方式

這個相對比中文的筆畫組合要好很多了,欲知詳情(正則的元字符用法)請點擊文章首部的相關文件推薦,我只做一下分類總結(沒法子,功力不足,小弟我目前只站在他們的腳尖上。)。

由於英文單詞由字母組成,所以字母對單詞的特性就顯現出現了,如在一個單詞中,某字母或某組字母出現的次數、自定義範圍內的字符、各種字符的分類。無論如何搗鼓,都是人類書寫的習慣。放大招如下表:

擴展正則(ERE)兼容基礎正則(BRE)
shell通配符 正則表達式元字符
說明 數量 符號 數量 說明 特點 所屬
任意字符及數量 0 ~ 無限個 * 0~ 無限 對前一個字符或一組字符定義至少重復出現的次數範圍0~無限次 數量類 基礎正則
. 1 一個任意的字符 數量類 基礎正則
+ 1 ~ 無限 對前一個字符或一組字符定義至少重復出現的次數範圍1~無限次 數量類 擴展正則
一個任意的字符 1 0 ~ 1 對前一個字符或一組字符定義至少出現0或1次 數量類 擴展正則
{n,m} n ~ m 對前一個字符或一組字符定義至少重復出現的次數範圍n~m次 數量類 擴展正則
{n,} n~ 無限 對前一個字符或一組字符定義至少重復出現的次數範圍n~無限次 數量類 擴展正則
{,m} 0~m次 對前一個字符或一組字符定義至少重復出現的次數範圍0-m次 數量類 擴展正則
{m} m 對前一個字符或一組字符定義重復出現m次 數據類 擴展正則

touch {1..2}.txt

touch {a..c}.txt

序列1 ~ 序列2 { 序列1..序列2 }
[ 字符1 ... 字符n ] 1

中括號內的任意一個字符

[a-z] 表示小寫字母的任意一個

[A-Z] 表示大寫字母的任意一個

[0-9] 表示數字的任意一個

[^0-9] 表示任意一個字符但不能是數字

[i s,_-] 表示只能是字母i,s,空格,逗號,減號中的任意一個

範圍類

(集合類)

基礎正則
[:alpha:] 1

等價於[a-zA-Z],即是26個大小寫英文字母

調用方式 [[:alpha:]]

字符分類 基礎正則
其余的字符分類

其他[:系列:]的,到推薦的文章或度一下就有一噸糧食了。

字符分類 基礎正則
\W
1
非\w的所有可見或不可見的任意字符

字符分類

基礎正則
\w 1 大小寫英文字母,數字,下劃線

字符分類

基礎正則
\S 1 任意一個可見的字符(理解用筆在紙上能寫出的符號都是可見)

字符分類

基礎正則
\s 1 非可寫的字符(理解無需用筆在紙上寫出的字符,如空格)

字符分類

基礎正則
^ 位置類 基礎正則
獲取變量值 $ 位置類 基礎正則
\b \< 單詞首 ;\> 單詞尾,使用方式與 \b 基本一致 位置類 基礎正則
\B 位置類 基礎正則
字符或組 | 字符或組 1 左邊或右邊的字符或一組字符只能出現其一 2選1 擴展正則
1或多個字符 1

功能一:將括號裏面的字符組成一組

功能二:可以給某些搜索命令(sed,grep)做反向引用

分組 擴展正則

\W,\S,\w,\s,及其他的字符分類都很好用。下圖是關於大S配小w,小S配大W的人脈關系圖

技術分享圖片

正則表達式工作寫真

正則表達式越模糊匹配,性能越低;反之性能越高(多思考等效的正則表達式是深入理解正則及調優的關鍵
正則的工作原理概念模型
可以在度度找一下RegexBuddy 這個正則軟件,能反映出正則表達式匹對內容大約需要多少次,正則表達式的性能調優參考
技術分享圖片

舉例:http://www.oldboyedu.com:80/html/html-tutorial.html

提取:http,www.oldboyedu.com,80,/html/html-tutorial.html,四段內容

分析:該url是一個復合詞(字母數字標點符號混合),從要求中,發現有兩個詞是同類詞,

一個是http,一個是80,另兩個是復合詞,一個是字母與點號,一個是字母斜線減號點號組成。其中,:或//要去掉

基本思路,使用二選一的方式,將二選一變成多選

基礎解題關鍵:如何將內容分解對應的詞或復合詞

1:同類詞http、80,是同屬一類字符 --> \w+ 或 [a-z0-9]+ 就可以輕松啪它下來了

2:復合詞www.oldboyedu.com.cn 域名類 --> 特點就是.xxx是重復的 --> \w+(\.\w+)+

3:復合詞/html/html-tutorial.html 路徑類 --> 固定/html/後面可以無限任意字符 -->/\w+/.*

答案:

[root@s1 ~]# a=http://www.oldboyedu.com:80/html/html-tutorial.html

[root@s1 ~]# echo $a | grep -oE ‘[a-z]+|\w+(\.\w+){2}|[0-9]{2}|/\w+/.*‘ #四個表達式的順序與url的四個內容一致,解法一:一一對應

[root@s1 ~]# echo $a | grep -Eo ‘\w+|\w+(\.\w+)+|/\w+/.*‘ #\w+ 匹配出 http 及 80,解法二:提取同類的字符為一類

[root@s1 ~]# echo $a | grep -oE ‘[a-z.0-9]+|[^0-9]+$‘ #[^0-9]+$ 匹配出 /html/html-tutorial.html ,解法三:與解法二類似,引用位置關系

機制解題的關鍵:在理解基礎解題的基礎上,搭配*可變0及正則匹配流程

[root@s1 ~]# echo $a | grep -oE ‘(/\w+/.*)*([^:/])*‘

解題過程:

1 (/\w+/.*)* 由於有*,整個表達式可以變0,所以從url的第一個字符開始匹對都失敗,直到/html/html-tutorial.html 才匹對成功,產生占有字符。

2 匹對過程: (/\w+/.*)* 已經匹對完整個內容了,但正則表達式 ([^:/])* 還沒有匹對,所以 ([^:/])*從頭開始匹對

3 貪婪與回溯:當 ([^:/])* 將/html/html-tutorial.html分解多個單詞,而 (/\w+/.*)* 就一個單詞,按貪婪原則 ,(/\w+/.*)*勝出。

註意:一個正則表達式產生占有字符,不代表其他表達式就不會對該占有字符對應的內容重新匹對,因為占有字符的最終確定是貪婪機制

占有字符零寬度是正則匹對原理的基礎

占有字符主要是對字符 [ 組合 ] 的排序搜索方式的工作機制:核心就是正則表達式不會重復匹對已經匹配出結果的內容,及得出臨時的結果(占有字符)。

使用 RegexBuddy 幫助理解占位符,回溯,貪婪
[root@server01 ~]# echo "abc123" | grep -E --color a.*1.*  
abc123
[root@server01 ~]# 

匹對過程

a #正則表達式第一個是字符a本身,這個直接匹對上

abc123 # 表達式a.*中的.*直接匹對後續的bc123,因為.*代表任意無限的字符組合,體現的貪婪機制

abc123 #回溯開始。因為1.*表達式中的1是字符本身,優先級比上一個表達式a.*中的.*要高,所以要產生回溯。

abc12 #回溯要回溯到那個地點才行能?理論上要證明表達式的字符1是在內容的字符排序中的第一個出現,並且在與a.*所對應的字符串中沒有1,那麽a.*所對應的字符串就是占有字符

abc12 #回溯開始。

abc1 #還不能證明表達式字符1是在內容的字符排序中的第一個出現,但記錄下第一次遇到字符1及位置

abc1 #回溯開始。

abc #a.*中.*匹對成功,並且沒有字符1,故a.*的占有字符產生(就是內容的abc)。也就是a.*可以退出這個正則匹對的舞臺了。那麽剩下的就到1.*上陣了

abc1 #1.*正則表達式中的字符1與內容的字符1匹對成功

abc123 #1.*完成匹對內容的123(數字123就是占有字符),到此正則的比對完成。

零寬度主要是對字符 [ 組合 ] 位置搜索方式的工作機制:核心就是讓正則表達式在那個位置開始匹對,後續工作交由對字符 [ 組合 ] 的排序搜索方式接管

零寬度一般在一組表達式中有多選一時生效
[root@server01 ~]# echo "abc123" | grep -Eo --color ^(a..|1..)
abc
[root@server01 ~]# echo "abc123" | grep -Eo --color a..|1..   
abc
123
[root@server01 ~]# 

分析過程

正則表達式 ^(a..|1..)中的 a.. 在內容的開始位置開始比較,1.. 依然在內容的開始位置開始比較,所以最終結果只能是 a.. 正則表達式能匹對abc123中的abc

正則表達式 a..|1.. 的原理基本上,同上述的對字符 [ 組合 ] 的排序搜索方式差不多了。

GNU/Linux 正則表達式與三劍俠(grep,sed,awk)(精)