④ 重复
用刚刚学过的正则表达式的语法,可以把两位数描述成/ \d\d /,把四位数描述成/ \d\d\d\d /。但是还没有一种方法可以用来描述具有任意多数位的数字,或描述字符串,这个字符串由三个字母以及跟随在字母之后的一位数字构成。这些较复杂的模式使用的正则表达式语法都指定了该正则表达式中的一个元素重复出现的次数。
指定重复的字符总是出现在他们所作用的模式之后。由于某种重复类型相当常用,所以有一些特殊的字符专门用于表示这种情况。例如+号匹配前一模式的一个或多个副本。下表总结了这些语法:
字符 | 含义 |
{n,m} | 匹配前一项至少n次,但是不超过m次 |
{n,} | 匹配前一项n次,或更多次 |
{n} | 匹配前一项恰好n次 |
? | 匹配前一项0次或1次。等价于{0,1} |
+ | 匹配前一项1次或多次 |
* | 匹配前一项0次或多次 |
在使用重复字符*和?时要注意,由于这些字符可能匹配前面字符的0个实例,所以它们允许什么都不匹配。例如正则表达式/a*/实际上与字符串“bbbb”匹配,因为这个字符串含有0个a。
⑤ 非贪婪的重复
上表列出的重复字符可以匹配尽可能多的字符,而且允许接下来的正则表达式继续匹配。因此我们说重复是“贪婪的”。可以以非贪婪的方式进行重复(在JavaScript 1.5和其后的版本中可以做到,这是Perl5的一个特性,在JavaScript 1.2中没有实现它),只需要在重复字符后面加问号即可。例如正则表达式/a+/匹配一个或多个字符a。将其应用到字符串"aaa"上时,它与三个字母都匹配。但是/a+?/只匹配一个或多个必要的字母a。将其应用到同样的字符串上时,该模式只匹配第一个字母a。
使用非贪婪的重复生成的结果并不总是与期望一致。考虑模式/a*b/,它匹配0个或多个字母a后跟随字母b。在应用到字符串“aaab”上时,它匹配整个字符串。现在使用非贪婪的重复版本/a*?b/,它应该匹配字母b,通过在字母b前加最少的字母a。在应用到同一个字符串"aaab"上时,读者可能以为它只匹配最后一个字母b。但事实上,这个模式也匹配整个字符串,和该模式的贪婪版本一样。这是因为正则表达式模式匹配是在寻找字符串中第一个可能匹配的位置。该模式的非贪婪版本在字符串的第一个字符处不匹配,所以该匹配将返回,甚至不考虑对后面的字符进行匹配(实话实说,这段话我自己没看懂,觉得怪怪的,先写在这吧,有空再来研究)。