重复字符
学习正则表达式中的乘法操作。
简写字符
在学习重复字符之前,我们先来了解表示数字 0-9、小写字母 a-z 和大写字母 A-Z 分别及组合的简写字符。你对范围字符及其在字符集中的用法已经相当熟悉了。在之前的挑战中,你编写了一个包含两个字符集 [^A-Za-z0-9_] 的正则表达式。挑战:理解负向字符集。与其逐一写出这些字符,我们可以使用 \w(反斜杠加小写 w)来更简洁地表示单词字符集。同样,负向单词字符集则用反斜杠加大写 W 表示。
以下是所有简写字符的列表:
| 简写符 | 说明 | 等价形式 |
|---|---|---|
| \W | 非单词字符 | [^a-zA-Z0-9_] |
| \w | 单词字符 | [a-zA-Z0-9_] |
| \S | 非空白字符 | [^ \t\r\n] |
| \s | 空白字符 | [ \t\r\n] |
| \D | 非数字 | [^0-9] |
| \d | 数字 | [0-9] |
现在你应该明白为什么我们不需要转义普通字符了。这种技巧使正则表达式更易读,并降低了其复杂度。
1var str = "222-4423-451" 2console.log( str.match(/\d\d\d/g) ) 3// 匹配所有三位数字的组合 4 5var str = "ab1c-x1c1-4uqr"; 6console.log( str.match(/\w\w\w\w/g)); 7// 匹配所有包含四个单词字符的组合 8 9var str = "ab1c-,-,x1c1-,-,4uqr"; 10console.log( str.match(/\W\W\W\W/g)); 11// 匹配所有不包含任何单词字符的四字符组合
重复字符的需求
在许多之前的挑战和代码任务中,你编写过包含相同组重复出现的正则表达式。例如,为了查找电话号码记录,可以使用字符集并重复它。你会写出类似 /\([0-9][0-9][0-9][0-9]\)-\([0-9][0-9][0-9]\)-\([0-9][0-9][0-9]\)/ 的正则表达式。在这种情况下,要匹配合法的电话号码,必须在正则表达式中重复字符集九次。虽然在这种情况下可以手动写出九次,但在更大的字符集中,这会变得非常繁琐。假设你需要查找长度为二十个字符的单词,每个字符可以是大写或小写。如果每次都写一次字符集,需要重复二十次,而正则表达式提供了一种重复字符的方法来解决这个问题。
重复字符的使用
重复字符非常重要,因为它们避免了重复书写相同的字符或字符集。简单来说,它们的作用类似于乘法。
让我们解决上面的问题。使用简写字符重写上述正则表达式:/\(\d\d\d\d\)-\(\d\d\d\)-\(\d\d\d\)/。虽然正则表达式看起来稍微简洁了一些,但重复字符集的基本问题仍未解决。正则表达式提供了一种重复字符来处理这个问题。接下来我们学习重复字符,然后再次解决该问题。
需要注意的是,重复字符仅作用于其前一个元素,即紧邻在其前面的那个元素。
重复字符的类型
正则表达式有三种重复字符:
*前面的项目出现零次或多次。+前面的项目出现一次或多次。?前面的项目出现零次或一次。
使用重复字符匹配文本的示例
再来看一个例子。假设你想匹配文本 "good"、"goodssss"、"goodss"。这三个文本都包含 "good" 子串的一次重复。接下来的部分略有不同,是字符 "s" 的重复。每个文本中 "s" 出现零次或多次。为此,可以使用重复字符 *,正则表达式为 /goods*/g。星号放在 "s" 后面,是因为你只想让 "s" 重复。在 "good" 中 "s" 出现 0 次,在 "goodssss" 中出现 4 次,在 "goodss" 中出现 2 次。
再看另一个字符 ?。例如,如果你想匹配 "apple" 和 "apples"。在这两个文本中,字符 "s" 出现 0 次或 1 次。使用 ? 字符来处理这种情况,正则表达式为 /apples?/。它会匹配 "apple",由于 ? 加在 "s" 后面,"s" 可以出现 0 次或 1 次。因此,这个正则表达式能同时匹配 "apple" 和 "apples"。
另一个字符 + 用于匹配前面的字符一次或多次,意味着至少出现一次。例如,要匹配 "god" 和 "good"。观察发现,"g" 和 "d" 是固定的,但 "o" 至少出现一次。虽然可以用 *,但它也会匹配 "gd" 和 "goood"。为了避免匹配像 "gd" 这样的情况,可以使用 +。正则表达式为 /go+d/,它能匹配这两个文本。要避免匹配 "goood",后面还会介绍一个特殊字符。
1var str = "good goodssss goodss" 2console.log( str.match(/goods*/g) ); // 使用星号 3 4var str = "god good" 5console.log(str.match(/go+d/g)); // 使用加号 6 7var str = "apple apples" 8console.log(str.match(/apple?/g)) // 使用问号
挑战:结合简写字符与重复字符
编写正则表达式,匹配以下格式的文本:(至少一位数字,后跟至多一位单词字符)-(至多一位数字,后跟至少一位空格字符)-(至少零次非空格字符,后跟至少一位非单词字符)。编写时请使用简写字符。

1var RegEx = function(){ 2 // 例如:return "/xyz/"; 不需要标志 3 return 4}
上述挑战的解决方案
通常,解决问题的方法是将其分解为几个部分:
- 所有括号和圆括号都是常量,可以通过转义括号来处理。
- 第一组要求至少出现一次,显然应使用
+,且需要数字,因此\d+是答案。第二组是至多一个单词字符,即最多出现一次,因此加上?。第一部分完成后,正则表达式为/\(\d+\w?\)/。 - 第二组是至多一个数字
\d?和至少一个空格字符\s+。正则表达式变为/\(\d+\w?\)-\(\d?\s+\)/。 - 第三部分是至少零次非空格字符,使用
*,因为它的特性是重复前一个字符零次或多次。因此是\S*,后接至少一个非单词字符\W+。最终的正则表达式为/\(\d+\w?\)-\(\d?\s+\)-\(\S*\W+\)/。
重复字符解决了正则表达式中的大多数问题,使正则表达式更加清晰易读。