5.1 有多个匹配
通过前面的学习,我们已经把正则表达式模式匹配操作的基础知识全都介绍给了大家,但我们给出的每个例子都有一个非常严格的限制。现在,请大家思考一下,如何构造出一个匹配电子邮箱地址的正则表达式。
电子邮件的地址的基本格式应该是这样的: name@host.suffix
,利用前前一章讨论的元字符,你可能会写出一个如下所示的正则表达式:
\w@\w\.\w
\w
可以匹配所有的字母、数字和下划线(下划线在邮箱地址里面是合法的)。@字符不需要转义,但 .
字符需要。
这个正则表达式本身没有任何错误,可它几乎没有任何实际的用处--它只能匹配a@b.c这种每个部分只有一个字符的邮箱地址。导致这一结果的关键是 \w
只能匹配单个字符,而我们无法预知邮箱地址的各个字符会有多少个字符。举个最简单的例子,下面这些都是合法的邮箱地址,但它们@前后的字符数量都不一样。
mahuateng@qq.com
mayun@alibaba.com
mayun@alibaba.inc.com
liyanhong@baidu.com
yanhong.li@baidu.com
想要解决这类问题,我们需要一种能够匹配多个字符的办法,这可以通过使用几种特殊的元字符来做到。
5.1.1 匹配一个或多个字符
要想匹配同一个字符(或字符集合)的多次重复,只要简单地给这个字符(或字符集合)加上一个 +
字符作为后缀就行了。 +
匹配一个或多个字符(至少一个,不匹配 0 个的情况)。比如, a
匹配 a 本身, a+
匹配一个或多个连续出现的 a。类似地, [0-9]
匹配任意单个数字, [0-9]+
将匹配一个或多个连续的数字。
在给一个字符集合加上 +
后缀的时候,必须把 +
放到这个字符集合的外面。比如说 [0-9]+
是正确的, [0-9+]
则不是。 [0-9+]
其实也是一个合法的正则表达式,但它匹配的不是一个或多个数字,而是匹配 0 到 9 和+构成的字符集合中的一个。虽然合法,但不是我们需要的东西。
重新回到电子邮件的例子,我们这次将使用 +
来匹配一个或多个字符:
\w+@\w+\.\w+
mahuateng@qq.com.欢迎来到正则表达式教程mayun@alibaba.com.这个例子是匹配邮箱的mayun@alibaba.inc.com上面例子中的5个邮箱这次能匹配出来吗?liyanhong@baidu.com试试看吧yanhong.li@baidu.com
这个正则表达式把上面例子中的 5 个邮箱,但其中有 2 个不够完整。为什么会这样?因为我们构造这个正则表达式的时候只想到在@字符后面会有一个.字符分开名称和域名,没有想到@字符的前面和后面会有不止一个.字符。因此,虽然 mayun@alibaba.inc.com 和 yanhong.li@baidu.com 都是完全合法的邮箱地址,但这个正则表达式只能匹配 mayun@alibaba.inc 和 li@baidu.com。因为 \w
只能匹配字母和数字字符,不能匹配中间出现的.字符。
要想干净彻底的解决这个问题,我们需要匹配 \w
或.。用正则表达式的术语来说就是,我们需要匹配这字符集合 [\w.]
。下面是上面例子的改进版本:
[\w.]+@[\w.]+\.\w+
mahuateng@qq.com.欢迎来到正则表达式教程mayun@alibaba.com.这个例子是匹配邮箱的mayun@alibaba.inc.com上面例子中的5个邮箱这次能匹配出来吗?liyanhong@baidu.com试试看吧yanhong.li@baidu.com
问题似乎得到了圆满的解决。 [\w.]+
将匹配字符集合 [\w.]
(字母、数字、下划线和.)的一次或多次重复出现,yanhong.li 和 alibaba.inc 完全符合这一条件。
这个正则表达式的最后一部分是 \w+
而不是 [\w.]+
,你知道这是为什么吗?把 [\w.]+
用作这个模式会在匹配结果的前 2 个出现问题,你不妨点击下面“去试试”看看。
细心的你可能已经注意到了,我们并没有对字符集合 [\w.]
里的 .
进行转义。尽管如此,它还是把原始文本里面的 . 字符给匹配出来了。一般来说,当在字符集合里面使用的时候,像 .
和 +
这样的元字符被解释为普通字符,不需要转义。但转义了也能用, [\w.]
和 [\w\.]
是一样的。
5.1.2 匹配零个或多个字符
+
匹配一个或多个字符,但不匹配零个字符—— +
最少也要匹配一个字符。那么,如果你想匹配一个可有可无的字符——也就是该字符可以出现零次或多次的情况,你该怎么办呢?这种匹配需要用 *
元字符来完成。 *
的用法与 +
完全一样——只要把它放在一个字符(或一个字符集合)的后面,就可以匹配该字符(或字符集合)连续出现零次或多次的情况。比如说,模式 yanhong.*li
将匹配 yanhongli、yanhong li、yanhong-li 和其他类似规律的组合,为了演示 +
和 *
的区别,我们来看两个匹配电子邮件地址的例子。先看第一个
[\w.]+@[\w.]+\.\w+
大家好,我是何方,我的邮箱是.xxx@xxx.xxx
[\w.]+
匹配字符集合 [\w.]
(字母、数字、下划线和.)的一次或多次重复出现,而 .xxx 完全符合这一条件。这显然是一个打字错误(原始文本里多了一个.),但这并不是我们这里最关心的问题。问题的关键在于:虽然 . 是电子邮件地址里的合法字符,但把它用作电子邮件地址的第一个字符就不合法了。
一个邮箱地址可以有任意多个字符,但它的第一个字符不能是.。根据这一要求,我们真正需要的是一个如下例子所示的模式:
\w+[\w.]*@[\w.]+\.\w+
大家好,我是何方,我的邮箱是.xxx@xxx.xxx
这个模式看起来相当复杂,但并不难理解。开头的 \w+
负责匹配电子邮件地址里的第一个字符(一个字母数字字符,不包括.字符)。接下来的 [\w.]*
负责匹配电子邮件地址里第一个字符之后、@字符之前的所有字符——这个部分可以包含零个或多个字母数字字符和.字符。至于这个模式的其他部分,我们已经在 第四章 里解释过了。在这个例子里,解决问题的关键是能不能想到用 [\w.]*
来匹配字符集合 [\w.]
(字母数字字符、下划线和.)的零次或多次重复出现。
可以把 *
理解为一个用来表明这样一种含义的元字符:“在我前面的字符(或字符集合)是可选的”。 *
与 +
的区别是: +
匹配一个或多个字符(或字符集合),最少要匹配一次; *
匹配零个或任意多个字符(或字符集合),可以没有匹配。
5.1.3 匹配零个或一个字符
另一个非常有用的字符是 ?
。 ?
只能匹配一个字符或字符集合的零次或一次出现,最多不超过一次——请仔细体会 ?
与 +
和 *
的区别之处。如果需要在一段文本里面匹配某个特定的字符或字符集合,而该字符可能出现、也可能不出现, ?
无疑是最佳的选择。
请看下面的例子:
http://[\w./]+
欢迎大家来到何方的个人小站 http://iamhefang.cn ,访问 https://iamhefang.cn 更加安全哦
这是一个用来匹配 URL 地址的模式: http://
是普通文本,只能匹配本身;随后 [\w./]+
匹配字符集合 [\w./]
(字母、数字、下划线、.和/)的一次或多次重复出现。这个模式只匹配到了第一个 URL 地址 ( http://iamhefang.cn ) ,没能匹配到第二个 ( https://iamhefang.cn ) 。简单的在 http
后面加上一个 *
并不能真正解决这个问题,因为那会使得“httpsssssss://”也会被匹配出来。
这要怎么处理呢?看下面这个例子:
https?://[\w./]+
欢迎大家来到何方的个人小站 http://iamhefang.cn ,访问 https://iamhefang.cn 更加安全哦
这个模式的开着部分是 https?
。 ?
在这里的含义是: ?
问号前面的字符要么不出现,要么只出现一次。
也就是说, https?://
既可以匹配"http://",也可以匹配"http://"。
注意
?
、 +
、 *
是元字符,如果需要匹配它们本身,就需要在它们前面加 \
。
[\?\+\*]
1+1*1=2, right?