下面的内容是一个 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