正则表达式:模式匹配入门 · 第 3 / 6 节

第 3 课:控制重复次数的量词

本课目标:

  • *+? 重复前面的条目。
  • {n}{n,m} 固定精确或有界的次数。
  • 说出量词附着在什么上(它前面紧挨着的单个条目)。

先修条件:第 1-2 课(字面量、字符类、\d) | 上一篇 << 02 | 下一篇 04 >>

一个字符类匹配一个字符,可数据是成串来的

上一课里,每个字符类都恰好匹配一个字符。真实数据不会一次只来一个字符:邮政编码是五位数字,用户名是一串单词字符,电话号码是一堆数字加上可能出现的连字符。如果一个字符类只匹配一个位置,怎么匹配“一整串”?这正是量词的全部工作:这族元字符说明它们前面那个东西重复多少次。要是搞错量词抓住的是“前面的哪个东西”,你的计数就会落在错误的位置上。

讲解

量词(quantifier)紧跟在一个条目后面,控制该条目重复多少次。有三个你会不停用到1

  • *:前面的条目,重复 0 次或更多。/bo*/ 匹配 “b”(零个 “o”)也匹配 “boooo”。
  • +:前面的条目,重复 1 次或更多。/a+/ 匹配 “candy” 里的那一个 “a”,也匹配 “caaandy” 里的全部 “a”1
  • ?:前面的条目,出现 0 次或 1 次(可选)。/colou?r/ 同时匹配 “color” 和 “colour”,因为 “u” 是可选的。

需要精确或有界的数量时,用花括号1

  • {n}:恰好 n 次。/a{2}/ 匹配 “aa”。
  • {n,m}:至少 n 次、至多 m 次。/a{1,3}/ 匹配一到三个 “a”。
  • {n,}n 次或更多,没有上限。

下面是让人栽跟头的细节:量词附着在它前面紧挨着的单个条目上,而不是整个模式上。在 /ab+/ 里,+ 只作用于 “b”,所以它匹配 “ab”、“abb”、“abbb”:一个 “a” 后面跟一个或多个 “b”。“a” 不会被重复。这个“前面的条目”可以是字面量、字符类,或(后面课里的)分组,但永远只是左边的那一个 token。

一句下一课才会兑现的预警:*+贪婪(greedy)的:它们能抓多少重复就抓多少。/a+/ 在 “caaandy” 上拿走全部三个 “a”,不是一个。我们会在第 6 课把这个行为(以及如何反转它)当作全部重点。

完整示例(跟着做)

你想匹配 “09:30” 这样的时间:两位数字、一个冒号、两位数字。用字符类加计数拼出来:

一步步看:\d{2} 的意思是恰好两位数字;: 是一个字面量冒号;第二个 \d{2} 又是两位数字。“09:30” 严丝合缝地符合这个形状,所以 testtrue。“9:30” 失败,因为 {2} 要求冒号前有两位数字,这里只有一位。每个量词都附着在它前面紧挨着的 \d 上:不附着在冒号上,也不附着在整个模式上。

你来试试(填空示例)

你想匹配一个话题标签:一个 # 后面跟一个或多个单词字符(所以 #a#regex101 都匹配,孤零零的 # 不匹配)。填上量词:

答案:空格处填 +,得到 /#\w+/# 是字面量,\w+ 的意思是“一个或多个单词字符”。因为 + 至少要求一个,光秃秃的 “#” 会失败(它后面有零个单词字符),而 “#regex101” 匹配。如果你填的是 *,孤零零的 “#” 也会匹配,因为 * 允许零个:这正是你现在可以主动做出的“0 个起步还是 1 个起步”的选择。

小结 + 下节课预告

量词说明它们前面那个条目重复多少次:*(0 次起)、+(1 次起)、?(0 或 1 次)、{n}(恰好 n 次)、{n,m}(n 到 m 次)。每个量词都附着在左边的单个 token 上,*/+ 默认贪婪。你现在可以匹配长度可控的字符串段了。但 /\d{5}/ 这样的模式仍然匹配长字符串里任何位置的五位数字:它还说不出“并且周围没有别的东西”。下一课我们加上锚点,把匹配钉在开头、结尾或词边界上。

Footnotes

  1. MDN: Quantifiers — https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions/Quantifiers 2 3

练习

01

在你的控制台里,定义 const s = "aaa bb c";。先预测再运行:s.match(/a+/)、s.match(/b*/) 和 s.match(/z*/)。特别注意 * 在没有东西可匹配时返回什么。

第 1 级(热身)
完成标准 · 本地勾选
02

为 “90210-1234” 这样的美式 ZIP+4 写一个模式:五位数字、一个连字符、然后四位数字。用 "90210-1234"(应当通过)和 "90210"(应当失败)测试它。然后解释为什么 /\d+-\d+/ 是个更差的写法。

第 2 级(进阶)
完成标准 · 本地勾选

我的笔记

记下想法、痛点、没懂的地方。只写进这门课的附录,正课文件不动。