正则表达式的应用
正则表达式Regular Expression
一、 什么是正则表达式
1.1 正则表达式简介
所谓正则表达式,实际上就是用来描述某些字符串匹配规则的工具,简单地说,正则表达式是对文本进行过滤的工具。而正则表达式之所以拥有过滤文本的功能,是因为它定义了一系列的元字符,通过元字符配合其他普通字符来表达出一种规则(匹配规则),只有符合该规则的文本才能保留下来。由于正则表达式语法简练、功能强大,得到了许多变成语言的支持,包括Java、C++、Perl以及Shell。
比如ls .txt。通常情况下,我们称“*”为通配符。当shell遇到该符号时,会将其解释为“任意的字符串”。与通配符类似,正则表达式也是用来匹配文本的,与之相比,正则表达式能够更加准确的描述用户的需求。
正则表达式在Unix和Linux中得到广泛的应用,常见支持正则表达式的Unix工具如下:
grep命令族:用于匹配文本行
sed流编辑器:用于编辑文本
awk:用于处理字符串的语言
掌握正则表达式,可以更好地利用这些工具。
1.2 如何学习正则表达式
1)重点在于理解元字符
元字符在正则表达式中占核心地位,正则表达式最终是由元字符表达出来。理解和掌握元字符的涵义,才能达到灵活运用的地步。
2)掌握好正则表达式的语法
正则表达式之所以简练,是因为它有严格的语法。例如“*”它匹配该符号前面那一个普通字符出现0次或多次,也就是说,它的作用范围仅限于紧挨着该字符前面的一个字符。
二、 基本正则表达式(Basic Regular Expression,BRE)
又称标准的正则表达式,是最早指定的正则表达式规范,其所定义的元字符主要有以下几种:
1、 行首定位符 “^”
2、 行尾定位符 “$”
3、 单个字符匹配 “.”
匹配任意单个字符,包括空格,但不包括换行符“\n”
4、 限定符 “*”
匹配其前导字符可以出现任意次数(0次或多次)
5、 字符集合匹配 “[]”
匹配方括号中任意一个字符 //例如:[abc]、[0-9]、[A-Z]
6、 字符集合不匹配 “[^]”
不匹配其中列出的任意字符
在示例之前,先来用sed删除空行:
[root@mha_master opt]# sed -i "/^$/d" regexp.txt
示例1:过滤出以字母“a”开头的行
[root@mha_master opt]# grep "^a" regexp.txt
示例2:过滤出以“C”结尾的行
[root@mha_master opt]# grep "C$" regexp.txt
示例3:过滤出总共有3个字符,该字符串以’a’开头,紧跟着第二个字符是“b”,第三个字符也是最后一个字符为“c”的行
[root@mha_master opt]# grep '^abc$' regexp.txt
示例4:匹配以a开头,c结尾,中间为除了换行符之外的任意一个字符的行
[root@mha_master opt]# grep '^a.c$' regexp.txt
示例5:匹配以d开头,d结尾,中间为除了换行符之外的任意两个字符的行
[root@mha_master opt]# grep '^d..d$' regexp.txt //可以使用多个“.”匹配多个字符
示例6:匹配a和b之间没有s或者有多个s的行
[root@mha_master opt]# grep '^as*b$' regexp.txt
示例7:匹配出字符串,该字符串只有三个字符且以字母开头、第二个字符是数字,第三个字符为字母。
[root@mha_master opt]# grep '^[a-zA-Z][0-9][a-zA-Z]$' regexp.txt
示例8:只匹配出来“a8c”
[root@localhost 桌面]# grep '^a[^a-z]c$' regexp.txt
a c
a.c //前两行结果明显不符合期望
a8c
[root@mha_master opt]# grep '^a[^a-z|\.|\ ][a-z]$' regexp.txt
其他标准正则表达式支持的元字符:
7.次数匹配—数量词
x\{m,n\}
区间表达式(次数匹配),匹配字符x重复的次数区间。该表达式表示x最少重复m次,最多重复n次
x\{m,\}
表示x至少重复出现m次
x\{,m\}
表示x至多重复出现m次
x\{m\}
表示x重复m次
\{\}示例:
[root@localhost 桌面]# grep '^as\{2,3\}b$' regexp.txt
assb
asssb
[root@localhost 桌面]# grep '^as\{2,\}b$' regexp.txt
assb
asssb
[root@localhost 桌面]# grep '^as\{2\}b$' regexp.txt
assb
匹配出abbbbbc
[root@localhost 桌面]# grep '^ab\{5\}c$' regexp.txt
abbbbbc
匹配出电话号码(11位)
[root@A tmp]# cat 1.txt ab asb assb asssb 13912345678 18198765432 39718973748719749] 313141 [root@A tmp]# grep '^[0-9]\{11\}$' 1.txt 13912345678 18198765432
8.词首词尾匹配
\<
词首定位符,\取其转义之意,< 前,首,词首
\>
词尾定位符,\取其转义之意,> 后,尾,词尾
词首字、词尾子匹配符示例:
[root@mha_master opt]# grep "\<welcome" regexp.txt
welcome to vfast!
[root@mha_master opt]# grep "done\>" regexp.txt
well done!
9.向前引用 \(\)
定义字表达式的开始和结束位置,在后续正则表达式中可以通过转义字符来引用正则表达式。最多可以定义9个字表达式,通过\1~\9来引用。
如:
[root@localhost 桌面]# grep '\(love\).*\1' regexp.txt
love me tender,love me sweet!
字表达式\(love\).*\1,表示匹配两个love中间包含任意个字符的文本行,其中\1表示引用前面定义的第一个字表达\(love\)
三、 扩展的正则表达式(Extended Regular Expression,ERE)
扩展的正则表达式支持比标准的正则表达式更多的元字符,但扩展的正则表达式对有些标准正则表达式所支持的元字符并不支持(区间表达式次数匹配),但上面介绍的6种元字符是支持的,并且意义完全相同。下面重点来看下扩展的正则表达式中新增的元字符。
Unix命令:
egrep或者grep -E 、 sed -r
1) 限定符 “+”
限定前面的字符至少出现一次
限定符 “*” 限定前面的字符出现0次或多次
2) 限定符 “?”
限定前面的字符出现0次或1次
3) 竖线“|”和小括号“()”
竖线“|”表示多个表达式之间“或”的关系,语法为:
expression1|expression2|expression3…
小括号(分组)表示一组可选值的集合。竖线和小括号经常放在一起用,表示一组可选值。
4) 扩展正则表达式取消了次数匹配{m,n}语法中的转义符,在使用这种语法时,不需要再添加转义符也不能添加,添加会匹配失败。
总结:标准正则表达式元字符:^ $ . * [] [^] \{\}
扩展正则表达式元字符:+ ? “|”和“()” {}
示例1:匹配出a和c之间字符“c”至少出现1次的字符串
[root@localhost 桌面]# grep '^ac+c$' regexp.txt //基本正则写(不支持+符号),不行
[root@localhost 桌面]# grep -E '^ac+c$' regexp.txt //还得扩展的正则
acc
accc
示例2:匹配a打头,b结尾,中间有0个或一个s的字符串
[root@mha_master opt]# grep -E '^as?b$' regexp.txt
示例3:匹配字符串,该字符串共有三个字符,a打头,c结尾,中间是数字或者是字符
[root@mha_master opt]# grep -E '^a([a-z]|[0-9])c$' regexp.txt
或 [root@mha_master opt]# grep -E '^a([a-z0-9])c$' regexp.txt
如果还有大写字母:
[root@mha_master opt]# grep -E '^a([a-zA-Z0-9])c$' regexp.txt
标准正则中[]表示匹配其中的任意一个字符,也可用竖线加小括号来表达:
[abc] 等价于 (a|b|c)
下面三组也是等价的:
(Jeffrey|Jeffery)
Jeff(rey|ery)
Jeff(re|er)y
示例4:字符串a开头,b结尾,中间s至少出现一次,最多出现2次
[root@mha_master opt]# grep -E '^as{1,2}b$' regexp.txt
四、 正则表达式中的普通字符
正则表达式是由一系列字符组成,其中包括元字符和普通字符。前面看过了很多元字符,现在来了解普通字符该如何匹配。
通常情况下,普通字符通常结合方括号表达式表示:
[cC]hina
[^hello]
[a-zA-Z]
[0123456789]
[0-9]
除了这些之外,还可以使用posix字符集,POSIX字符集是为了在不同国家的字符编码中保持一致,而定义的一些特殊字符类(扩展的正则):
字符类 |
说明 |
[:alnum:] |
匹配任意一个字母或数字,等价于[a-zA-Z0-9] |
[:alpha:] |
匹配任意一个字母,等价于a-zA-Z |
[:digit:] |
匹配任意一个数字,等价于0-9 |
[:lower:] |
匹配任意一个小写字母,等价于a-z |
[:upper:] |
匹配任意一个大写字母,等价于A-Z |
[:space:] |
匹配任意一个空白字符,包括空格、制表符、换行符 |
[:blank:] |
匹配空格和制表符 |
[:graph:] |
匹配任意一个看得见的可打印字符,不包括空白字符 |
[:print:] |
匹配任意一个可以打印的字符,包括空白字符,但是不包括控制字符、EOF文件结束符 |
[:cntrl:] |
匹配任意一个控制字符(百度百科:控制字符),即ACSII字符集中的前32个字符,如:换行符、制表符等 |
[:punct:] |
匹配任意一个标点符号,如”[]”、”{}”、 ,“” |
[:xdigit:] |
匹配16进制数,即0-9、a-f以及A-F |
单词:
alphabet 字母表
digit 数字
blank 空白的
punctuation 标点符号
示例:过滤出符合指定格式的电话号码
[root@mha_master opt]# grep -E '400-[[:digit:]]{3}-[[:digit:]]{4}$' regexp.txt
400-123-5678
运算符的优先级:
运算符 |
说明 |
\ |
转义字符 |
[] |
方括号表达式 |
() |
分组 |
*、+、?、{m}、{m,}、{m,n} |
限定符 |
普通字符 |
按照从做到右的顺序 |
^、$ |
定位符 |
| |
或运算 |
演示分组“()”:匹配IP地址
[root@mha_master opt]# grep -E '^([[:digit:]]{1,3}\.){3}[[:digit:]]{1,3}$' regexp.txt
202.106.0.20
10.0.0.1
256.45.32.1 //这是一个不正确的IP
精确匹配:
grep -E "^([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])$" regexp.txt
练习:
1、从regexp.txt中匹配出书写正确的邮箱地址:
这里认为邮箱用户名至少是6~18位的字母和数字组成,邮箱账号均为163.com的邮箱。
[root@mha_master opt]# grep -E '^[[:alnum:]]{6,18}@163\.com$' regexp.txt
2、源文件url.txt的内容如下:
www.baidu.com
http://www.baidu.com
https://www.baidu.com
http://wwwbaiducom
baidu.com
baidu
匹配出以http或https开头,其后为“:”,并且含有“.”的串
[root@localhost 桌面]# grep -E 'https?.*\.' url.txt
http://www.baidu.com
https://www.baidu.com
3、Email匹配
示例文件内容为:
hfutwyy@qq.com
aaaa@
aaa@.com
_aaa@gmail.com
@@baidu.com
匹配以字母数字或者下划线开头的多个字符,其后有一个@之后有多个字母数字或者下划线,其中有一个.号
[root@localhost 桌面]# grep -E '^[[:alnum:]|_]*@[[:alnum:]|_]\.*' email
hfutwyy@qq.com
_aaa@gmail.com
4、匹配身份证号:18位
前17位必须为数字,最后一位是数字或字母
grep -E '^[0-9]{17}[0-9A-Z]$' danny.txt
5、校验用户名
[root@localhost 桌面]# grep -E '^[[:alpha:]][[:alnum:]|_]{5,17}@163.com' regexp.txt
heihei@163.com