正则表达式入门(3)——重复匹配
这个问题是:如何匹配连续多个重复出现的字符或字符集合?例如,如何匹配一个电子邮件的格式?
text@text.text
电子邮件的格式包含了三段,但我们不知道每一段的长度。
1.匹配一个或多个字符
在字符或字符集合后面跟一个“+”(加号),表示匹配1个或多个该字符或字符集合。例如,[0-9]+就表示一串任意长度的数字。
回到电子邮件的例子。电子邮件中的三个字段,其组成字符应该是\w类的,所以可以表示为:
\w+@\w+\.\w+
注意w是小写的,大写W表示“非”。
但是这还是有问题,因为有些电子邮件的地址中包含了“.”点字符(起这种邮件名真是蛋疼),那么\w是不包含点字符的。比如:
michael.jackson@moon.com
这样的地址,上面的正则只能匹配成jackson@moon.com了。
但是,还有些电子邮件地址有多级域名,例如:
tom.jerry@sina.com.cn
所以,要用[\w.]才能描述这种情况了。重新修改一下电子邮件的正则,应该是:
[\w.]+@[\w.]+\.\w+
已经开始有点看不懂了……这里要特别注意的是,字符集合中的“.”或者“+”等元字符,与字符集合外的规则不同,他们只表示自己,不需要转义。也可以说:
字符集合内(即方括号[]内)的语法与字符集合外是不同的,务必注意。
还有一点,+加号表示1个或以上,而不包括0个。如果要包括可有可无的情况,那么就用*(星号)替换+(加号)。
2.匹配零个或多个字符
考虑有这么一句话:
Hello, my email address is .ben@red.net.
如果用前面的正则,会匹配出这个结果:
.ben@red.net
显然前面多打了个“.”,而点字符在邮件地址中可以出现,却不能出现在开头,那就是不合法的。这个时候,我们要确保第一个字符是\w类才行。
再次修改邮件的正则格式:
\w+[\w.]*@[\w.]+\.\w
现在ok了,会自动把前面那个“.”给去掉了。注意[\w.]*表示可有可无。如果仍然用[\w.]+的话,则邮件名的@前面至少要有两个字符才能匹配了。
3.匹配零个或一个字符
问号(?)与点符号(.)的区别是:问号也是匹配任意单个字符,但可以有,也可以没有,而点符号隐含的意思是“必须有”。
例如,要匹配http和https,应该写:
https?
它表示http后面的s可有可无,都能匹配。
[\r]?与\r?的区别是什么?
这两种写法的匹配结果是一样的,当然带[]会更容易读一些。但实际的语义一样吗?这个问题留待以后研究吧。
4.匹配精确重复数
+和*匹配的字符数是任意长度,但如果要精确限定重复字符的个数,需要用{}元字符。再例如颜色值的表达式,是一个#后面跟6个十六进制字符。重复写6遍[A-Fa-f0-9]或者[[:xdigit:]]都可以,但还有简单的写法:
#[[:xdigit:]]{6}
就可以了。
5.重复匹配数量的区间
如果要匹配一堆长度在3位到8位之间的数字,该怎么写呢?
[0-9]{3,8}
就这么写,很简单,只包含长度在3位到8位之间的数字串,会把22或者987654321等长度不符合要求的字符串给过滤掉。
由此还可以推测出,如果要限制最小重复次数,或者最大重复次数,只要去掉逗号左右其中一个数字就行了。例如:
[a-z]{5,} //5位以上长度的连续小写字母串
[A-Za-z]{,30} //30位以下长度的连续字母串
6.“贪婪型”元字符和“懒惰型”元字符
比如有这么一句话:
living in <B>AK</B> and <B>HI</B>.
这是常见的html标记。如果要提取AK和HI,也许你会写成:
<B>.*</B>
但是这会悲剧的提取出下面这句结果:
<B>AH</B> and <B>HI</B>
中间的\和\都被(.*)给包括进去了。这是因为星号(*)和加号(+)都属于贪婪型元字符。所谓贪婪型元字符,就是从头到尾的去整体匹配,而不是从头开始顺序匹配,遇到第一个能结束匹配的位置就停止。如果要正确截取上面的例子,就需要使用懒惰型元字符,或者说是*或+的懒惰型版本。方法是在贪婪型元字符后面加个问号(?)。
*的懒惰型是*?
+的懒惰型是+?
{n,n}的懒惰型是{n,n}?
以此类推。注意,指定重复字符范围的语法{,}也属于贪婪型,它的懒惰型版本是{,}?。
将前面的正则改为:
<B>.*?</B>
就可以完美匹配了。当然作为html标记本身来说,还包括<b>
和</b>
这样的小写方式,如果需要匹配的话,应该是:
<[Bb]>.*?</[Bb]>
问题解决了。