正则表达式概述
学习之前,可以暂时把正则表达式理解为功能更高级的通配符(wildcard)。
在Shell里,可以通过通配符来匹配一些具有相似模式的字符串,比如下面的命令:
$ ls * # 列举所有的文件
$ ls *.c # 列举所有以".c"结尾的文件
$ ls 108?.c # 列举以108开头,后面跟一个任意字符,再以".c"结尾的文件
$ ls 108[56].c # 列举以108开头,后面跟5或6,再以".c"结尾的文件
$ ls 108[0-8].c # 列举以108开头,后面跟0~8中的任意一个,再以".c"结尾的文件
$ ls l08[!0].c # 列举以108开头,后面跟一个不为0的字符,再以".c"结尾的文件
其中,'*'、'?' 等就被称为通配符,因为他们可以匹配一个或多个符合规则的字符,具体的,这些通配符的作用如下:
- '*' 用于匹配零个或多个任意字符。
- '?' 用于匹配单个任意字符。
- '[]' 用于匹配可能出现的单个字符,比如[56]表示该位置可能出现5或6, 也可以使用范围的方式,比如[0-8]表示数字范围0~8,[a-i]表示字符范围a~i。
- '!' 用于排除单个字符。
通配符的作用就是用于字符串的匹配,但是在遇到比较复杂的匹配需求时,通配符就无能为力了,比如像“匹配以test开头,后面跟1个或多个数字,再跟3个非数字的字符,再以abcef中的一个或多个字符结尾的字符串”,或是匹配一个邮箱地址,只使用通配符的话就无法实现,这时,正则表达式就可以派上用场了。
正则表达式是比通配符功能更加强大的用于字符串模式匹配的工具,具体地,正则表达式可以实现以下功能:
- 字符串模式匹配,即验证字符串是否符合指定特征,比如验证一串字符是否是一个合法的邮箱地址;
- 在模式匹配的基础上,进行字符串分割,将字符串按规则分割成几个部分,以便于提取字符串,比如从邮箱地址中提取@前面的用户名;
使用正则表达式的最大问题是正则表达式有很多的流派(正则表达式“派别”简述 - Keep Coding),也就是在实现相同功能的情况下,不同流派的正则表达式可能有不同的写法。具体来说,正则表达式可以分为以下几类:
- POSIX基础正则表达式(basic regular expression, BRE)
- POSIX扩展正则表达式(extended regular expression, ERE)
- Perl兼容的正则表达式(Perl compatible reqular expression, PCRE)
关于这几个流派,PCRE一般用于编程语言,比如Perl, Boost.Regex, java.util.regex。BRE和ERE一般用于POSIX程序,比如sed, awk, grep等,其中sed默认使用BRE,awk默认使用ERE,而grep则可以通过选项选择使用哪种流派的正则表达式。关于这几个流派的正则表达式差异可以参考:正则表达式 BRE ERE PCRE 区别 | IT日记,本篇主要介绍PCRE。
学习正则表达式可以借助一些在线测试的网站,比如:在线正则表达式测试工具,Regexp在线调试 - 在线工具。
正则表达式规则
关于模式匹配
所谓模式匹配,其实就是给出一个模式串和目标串,然后判断目标串中是否存在匹配串。
模式串用以描述要匹配的字符串特征,可以包含用于模式匹配的元字符,也可以包含普通字符。目标串则可以是任何字符串,匹配串是目标串中符合模式串的实际字符串。
以上面的通配符举例,abc[de]f
就是一个模式串,这个模式串描述的字符串特征是“abc开头,后面接一个d或e,再接一个f”
。目标串可以是任何字符串,这里以目标串abcdefg
举例,在这个目标串里,不存在与模式串匹配的目标串。把目标串改成abcdfg
,则存在一个匹配串abcdfg
,匹配位置是从1开始,结束于5(下标从1开始)。如果把目标串改成abcdfgabcefg
,则存在两个匹配串abcdfgabcefg
,第一个匹配串起始于1,结束于5,第二个匹配串起始于7,结束于11。
模式串不一定要匹配整串目标串,只要部分匹配,就算匹配成功,甚至在一个目标串里可以存在多个匹配串。
正则表达式充当的就是模式串的作用,通过正则表达式可以描述一个待匹配的字符串特征。
正则表达式构成
参考:http://regexlab.com/zh/regref.htm
正则表达式其实就是一串用于描述字符串特征的字符串,包含普通字符和元字符。普通字符用于匹配目标串里的相同字符,比如正则表达式abc
,在匹配目标串abcdef
时,匹配的结果是成功,匹配到的内容是abc,匹配到的位置是开始于1,结束于3。元字符和Shell里的通配符功能类似,用于匹配一类字符,只不过正则表达式里的元字符数量比Shell里的通配符数量要多很多,功能也比通配符强大。
区分多种不同的正则表达式类型,搞清楚它们之间的区别和应用场景,以及放在代码中的转义字符处理,特别是C++中构造正则表达式时的反人类的转义写法。
几个实例,
notepad++中替换文本
匹配UUID
匹配邮箱