在编程中,经常会有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的工具。换句话说,正则表达式就是记录文本规则的代码。然而正则表达式的语法很令人头疼,即使对于经常使用它的人来说也是如此。下面我将简单介绍一下正则表达式,帮助大家快速入门。文中内容如有不妥之处,欢迎大家提出宝贵意见。
一、元字符(metacharacter)
表1 常用的元字符
符号 说明 .
匹配除换行符以外的任意字符
\w
匹配字母、数字、下划线、汉字
\s
匹配任意的空白符,包括:空格、制表符(Tab)、换行符、中文全角空格等
\d
匹配一位数字
\b
匹配单词的开始或结束,也就是单词的分界处
^
匹配字符串的开始
$
匹配字符串的结束
例子:
1)0\d{5}-\d{8}
匹配以0为开头,然后是5个数字,然后是一个连字符“-”最后匹配8个数字。
2)\ba\w*\b
匹配以字母a开头的单词,然后是任意数量的字母、数字、下划线或汉字。
3)\d+
匹配1个或更多连续的数字。
4)\b\w{5}\b
匹配5个字符的单词。
注意:
元字符^和$都匹配一个位置,这和\b有点类似。^匹配你要用来查找的字符串的开头,$匹配结尾。例如一个网站如果要求你填写的密码必须为6位到12位字符时,可以使用:^\d{6,12}$。
二、字符转义
为什么会有转义字符呢?如果你想查找某些特殊含义的字符,比如说元字符本身,这个时候直接查找是不合适的,因为元字符会被解释成别的意思,这个时候就会用到转义字符(\)。例如:C:\\Users匹配C:\Users。
三、限定符
表2 常用的限定符
符号 | 说明 |
---|---|
* | 重复零次或更多次 |
+ | 重复一次或更多次 |
? | 重复零次或一次 |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
{n,m} | 重复n至m次 |
例子:
1)user\d*
匹配user后面跟零个或更多个数字
四、字符类
表3 常用的字符匹配
符号 | 说明 |
---|---|
[abc] | 匹配字母abc |
[.?!] | 匹配标点符号.或?或! |
[a-z0-9A-Z] | 匹配一个英文字母或数字 |
[0-9] | 匹配任意一个数字,相当于\d |
例子:
1)\(?0\d{2}[) -]?\d{8}
匹配0个或1个(,然后是匹配一个0,后面匹配两个数字,然后是匹配)或空格或-中的0个或1个,最后匹配8个数字。
五、分支条件
正则表达式里的分支条件是指有很多种规则,如果满足其中的一种规则就应该予以匹配。分支条件的符号是|,用|将不同的规则分隔开来。
例子:
1)\(?0\d{2}\)?[- ]?\d{8}|0\d{2}[- ]?\d{8}
该正则表达式可以匹配两种类型的字符串:第一,匹配0个或1个(,后面匹配一个0,接着匹配两个数字,然后匹配0个或1个),后面匹配-或空格0个或者1个,最后匹配8个数字;第二,匹配一个数字0,然后匹配两个数字,接着匹配-或空格的0个或1个,最后匹配8个数字。
注意:
使用分支条件时,要注意各个条件的顺序。因为匹配分支条件时,将会从左到右的测试每一个条件,如果满足了某个分支的话,就不会再去管其他的条件了。
六、分组
当需要重复多个字符时,就会用到分组。将需要重复的多个字符用小括号括起来构成一个子表达式,这个子表达式就是分组。将这个子表达式看成一个整体,然后就可以指定这个子表达式的重复次数了。
例子:
1)匹配一个IP地址:
((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)
首先看一下第一个小括号里面的内容(2[0-4]\d|25[0-5]|[01]?\d\d?),这是一个子表达式。这个子表达式里面又有两个分支条件。先来看第一个分支条件,首先匹配一个数字2,然后匹配数字0-4中的任意一个,最后匹配任意一个数字。再来看第二个分支条件,首先匹配数字25,然后匹配0-5中的任意一个数字。最后看第三个分支条件,首先,匹配数字0或1中的0个或1个,然后,匹配一个任意的数字,最后匹配一个任意的数字。
第一个子表达式匹配完成之后,会匹配一个.。((2[0-4]\d|25[0-5]|[01]?\d\d?)\.)匹配完成之后,会作为一个分组继续匹配后面的语句,即重复这个分组3次。最后继续匹配后面的语句,后面的语句与第一个子表达式里面的语句相似,在此就不赘述了。
七、反义
如果想要查找除了小写字母之外,其他任何字符都行的情况。这个时候,用反义是比较方便的,下面是一些常用的反义代码。
表4 常用的反义符
符号 | 说明 |
---|---|
\W | 匹配任意不是字母,数字,下划线,汉字的的字符 |
\S | 匹配任意不是空白符的字符 |
\D | 匹配任意非数字的字符 |
\B | 匹配不是单词开头或结束的位置 |
[^a] | 匹配除了a以外的任意字符 |
例子:
1)\D+
匹配不包含数字的字符串
2)x[^a]+
匹配以x开头不包含a的字符串
八、后向引用
后向引用用于重复搜索前面某个分组匹配的文本,每个分组都会拥有一个组号,组号的命名规则是:从左向右,以左括号为标志,按照出现的顺序命名1,2,...。下面以一个例子具体展开说明。
\b(\w+)\b\s+\1\b的匹配原则是:首先匹配一个单词,然后是一个或多个空白符,最后是分组一中的内容。所以说,这个正则表达式最终可以匹配重复的单词,比如like like。
组名也可以自己设定,可以使用(?<xzw>\w+)或(?'xzw'\w+)来把上例的组名更改为xzw。
九、零宽断言
零宽断言是用来查找某些内容之前或之后(不包含内容本身)的东西的,即零宽断言是用于指定一个位置的,下面是常用的四种零宽断言。
表5 常见的4种零宽断言
符号 说明 (?=exp)
零宽度正预测先行断言,它断言自身出现的位置的前面能匹配表达式exp
(?<=exp)
零宽度正回顾后发断言,它断言自身出现的位置的后面能匹配表达式exp
(?!exp)
零宽度负预测先行断言,断言此位置的后面不能匹配表达式exp
(?<!exp)
零宽度负回顾后发断言,断言此位置的前面不能匹配表达式exp
十、懒惰匹配
所谓懒惰匹配就是指匹配尽可能少的字符,下面给出几个常用的懒惰限定符。
表6 常用的懒惰限定符
符号 | 说明 |
---|---|
*? | 重复任意次,但尽可能少重复 |
+? | 重复1次或更多次,但尽可能少重复 |
?? | 重复0次或1次,但尽可能少重复 |
{n,m}? | 重复n到m次,但尽可能少重复 |
{n,}? | 重复n次以上,但尽可能少重复 |
十一、补充内容
表7 常用分组语法
符号 | 说明 |
---|---|
\a | 报警字符 |
\b | 通常是单词分界位置,但如果在字符类里使用代表退格 |
\t | 制表符 Tab |
\r | 回车 |
\v | 竖向制表符 |
\f | 换页符 |
\n | 换行符 |
\e | Escape |
\0nn | ASCII代码中八进制代码为nn的字符 |
\xnn | ASCII代码中十六进制代码为nn的字符 |
\unnnn | Unicode代码中十六进制代码为nnnn的字符 |
\cN | ASCII控制字符。比如\cC代表Ctrl+C |
\A | 字符串开头,类似^ |
\Z | 字符串结尾或行尾 |
\z | 字符串结尾,类似$ |
\G | 当前搜索的开头 |
\p{name} | Unicode中命名为name的字符类 |
(?>exp) | 贪婪子表达式 |
(?<x>-<y>exp) | 平衡组 |
(?im-nsx:exp) | 在子表达式exp中改变处理选项 |
(?im-nsx) | 为表达式后面的部分改变处理选项 |
(?(exp)yes|no) | 把exp当做零宽正向先行断言,如果在这个位置能匹配,使用yes作为此组的表达式;否则使用no |
(?(exp)yes) | 同上,只是使用空表达式作为no |
(?(name)yes|no) | 如果命名为为name的组捕获到了内容,使用yes作为表达式;否则使用no |
(?(name)yes) | 同上,只是使用空表达式作为no |
好了。至此就是本文的所有内容了,相信大家现在对正则表达式已经有了一定的了解了吧。