下面的内容是一个 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:hemmingway@163.com
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})$

rich.john@sari.ac.cn
wangxf@163.com
rich.O.johl@hotmail.com

$ 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