跳到主要内容

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.comyanhong.li@baidu.com 都是完全合法的邮箱地址,但这个正则表达式只能匹配 mayun@alibaba.incli@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?
该内容基于 《正则表达式必知必会》 二度创作
转载请遵守原作者相关协议并注明本页地址
https://iamhefang.cn/tutorials/正则表达式/第五章-重复匹配/5.1-有多个匹配