下面的內容是一個 data1.txt 文本內容,裏面記錄了一些正則表達式的筆記
long long ago there is girl, she's name is little redhat..
long_long_long#long;long:long
This is a test txt...
my phone number is 18621735531
There are a lot of good books,
220123
12345
E-mail:[email protected]
new...............231592315y12#$@%#$@^%$^$@<>?{}|}S#$!@#%
ik
iek
ieek
ieeek
ieeeek
ieeeeek
ieeeeeek
iek22222
iekddddd
iekwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
iek shit up
this is iekkkk string
nekkkk
cek
dek
sekjjjd
# 組合描點 grep -n ^$ data1.txt, 可以濾出來空白行
#grep -n This is ^a data1.txt
#grep -n ^[0-9][0-9][0-9][0-9][0-9]$ data1.txt \
#grep -n ie*k data1.txt
一、錨點
鎖定行首 ^
鎖定行尾 $
組合錨點 ^$
二、單個字符匹配
字符組 [..]
[^...]
. 一個字符佔位符,不包括換行
* 匹配前一個字符出現任意次次數
=====================================我是分割線==================================
下面是擴展的 正則表達式
? 匹配前一個字符有或者沒有,就是0次要麼1次
+ 匹配前一個字符需要出現的,不管次數
模式匹配次數
{m} 精確的m次數
{m,} 大於m次,n爲無窮大
{m,n} 大於m次, 小於n次
圓括號聚合匹配格式
()
(||)
舉個列子:比如下面的命令匹配 iek 字符串
#grep -n -E ie\{1\}k data1.txt
#grep -n -E ie{1}k data1.txt
匹配 ie 出現一次的,不是2次,也不是 se,de,其他字符串
#grep -n -E ie\{1\} data1.txt
比如,給出下面一些字符串,想要匹配星期六的符串, Sat. 縮寫或者全寫 Saturday:
SatSomething
Satelse
Sat.
Saturday
# grep -n -E '^Sat(urday|.)?$' data1.txt
複雜的例子 一:匹配電話號碼,如下面四種形式
(223)456-7890
(223) 456-7890
223 456-7890
223 456-7890
223456-7890
223-456-7890
###223-456-7890
223.456.7890
223.456-7890
223-456.7890
分析,首先,開頭的 左邊圓括號 '\(' 可有可無的, 所以得到:
^\(?
再看 123 是三個數字的區號,美國電話號碼區號是以2開始的數字開始的,最大到9, 後兩個數字任意的,因此匹配區號是:
[2-9][0-9]{2}
接下來分析區號後面, 收尾的右圓括號 '\)' 可能存在,也可能不存在,單獨去取出來和左邊對應,匹配方式爲:
\)?
接下來,可能有一個空格或者沒有, 一個破折號 '-' 一個點號 '\.' ,可以用管道符號可圓括號處理得到:
(| |-|\.)
接下來是三位電話交換機號碼,沒有什麼特殊的
[0-9]{3}
接下來,交換機號碼後面可能有一個空格,一個破折號或者一個點號
( |-|\.)
最後是尾部的四位本地電話分機號碼:
[0-9]{4}$
最後,拼接起來整個模式爲:
^\(?[2-9][0-9]{2}\)?(| |-|\.)[0-9]{3}( |-|\.)[0-9]{4}$
最後查找匹配合格的電話號碼:
nfs@nfs-Lenovo:~$ grep -n -E '^\(?[2-9][0-9]{2}\)?(| |-|\.)[0-9]{3}( |-|\.)[0-9]{4}$' data1.txt
91:(223)456-7890
92:(223) 456-7890
93:223 456-7890
95:223456-7890
96:223-456-7890
98:223.456.7890
99:223.456-7890
100:223-456.7890
思考,這個regex還有個bug, 就是 223456-7890也是合法寫法電話,想要把這個case排除,新的匹配模式怎麼寫?
如果 區號 沒有被括號包圍,那麼一定需要一個 空格隔開。。。。。。。。。。。。。。
答題:
需要將 區號 部分重新提煉出來處理,分成有括號的區號和沒有括號的區號,有括號區號匹配如下:
^\([2-9][0-9]{2}\)
沒有括號的區號匹配如下:
^[2-9][0-9]{2}
再次做一個改變,將區號後面的符號提到前面處理,因次分別得到:
^\([2-9][0-9]{2}\)(| |-|\.)
和(這個模式後面不跟空格,只有破折號和點號)
^[2-9][0-9]{2}( |-|\.)
將這兩種case合併得到下面的模式可以匹配區號:
(^\([2-9][0-9]{2}\)(| |-|\.)|^[2-9][0-9]{2}( |-|\.))
最後合併得到新的電話號碼匹配模式:
(^\([2-9][0-9]{2}\)(| |-|\.)|^[2-9][0-9]{2}( |-|\.))[0-9]{3}( |-|\.)[0-9]{4}$
進行測試:
$ grep -n -E '(^\([2-9][0-9]{2}\)(| |-|\.)|^[2-9][0-9]{2}( |-|\.))[0-9]{3}( |-|\.)[0-9]{4}$' data1.txt
91:(223)456-7890
92:(223) 456-7890
93:223 456-7890
96:223-456-7890
98:223.456.7890
99:223.456-7890
100:223-456.7890
複雜列子二:匹配郵箱地址
E-mail格式爲:
username@hostname
username可以使用的字符有 字母數字字符以及一些特殊字符,如下:
1.點號
2.破折號
3.加號
4.下劃線
所以,username匹配方式爲:
^([a-zA-Z0-9_\-\.\+]+)@
接下來分析 hostname的服務器名字和子域名,這部分可以是字母數字字符,以及點號和下劃線:
([a-zA-Z0-9_\-\.]+)
這個模式可以匹配文本:
server
server.subdomain
server.subdomain.subdomain
接下來就是 hostname中的頂級域名部分,不考慮中文域名,頂級域名要是是2到5個字母組成的,頂級域名爲:
\.([a-zA-Z]{2,5})$
所以匹配郵箱地址爲:
^([a-zA-Z0-9_\-\.\+]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$
[email protected]
[email protected]
[email protected]
$ grep -n -E '^([a-zA-Z0-9_\-\.\+]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$' data1.txt
最後一個列子,匹配QQ號碼,QQ號碼是6個以上的數字,假設最大數字是13,不以0開頭的,匹配模式如下:
^[1-9][0-9]{5,}$
測試如下QQ號碼:
038216437
123
12345
382164370
281120661
754198142
###754198142
754198142##
1123564020
11111111111111111111111111111465
nfs@nfs-Lenovo:~$ grep -n -E '^[1-9][0-9]{5,12}$' data1.txt
9:220123
253:382164370
254:754198142
255:1123564020
nfs@nfs-Lenovo:~$ grep -n -E '^[1-9][0-9]{5,12}$' data1.txt
9:220123
253:382164370
254:754198142
255:1123564020
nfs@nfs-Lenovo:~$
匹配整數寫法,整數前面一個破折號表示負數,或者一個可有可無的 + 號,匹配模式如下:
^(|-|\+)
接下來是第一個數字,非0,後面不限,因此
[1-9][0-9]*$
合併得到正數的匹配寫法是:
^(|-|\+)[1-9][0-9]*$
測試整數:
-1203
5554
+7894
-2222222
#24545
# grep -n -E '^(|-|\+)[1-9][0-9]*$' data1.txt
再寫一個簡單的,匹配字母數字字符串。
^[a-zA-Z0-9]+$
# grep -n -E '^[a-zA-Z0-9]+$' data1.txt
匹配空行
#grep -n -E '^$' data1.txt
最後一個奇怪的測試:
([\\/$]* | ?:[\\/]*)
測試:
x:\test\test
z:/test1/test1
${datarootdir}/doc/${PACKAGE_TARNAME}
${datarootdir}/doc/man
# grep -E '([\\/$]* | ?:[\\/]*)' data1.txt