- 文档/教程
- 前端
【免费下载链接】en.javascript.info
Modern JavaScript Tutorial
正则表达式中的量词(quantifier)是构建复杂匹配模式的核心"积木":它们决定一个字符、字符类或[...]集合需要出现多少次。本文以现代 JavaScript 教程(en.javascript.info)正则专题为基础,系统讲解{n}、{n,m}、+、?、*五种量词的语义差异,并通过电话号码提取、小数匹配、HTML 标签解析等实战案例,配合仓库内置练习(1-find-text-manydots、2-find-html-colors-6hex)加深理解。读完本文,你将能独立设计出既精确又高效的重复匹配模式,并理解何时该用哪种量词。
为什么需要量词:从"单个数字"到"完整数字"
假设我们有字符串+7(903)-123-45-67,希望提取其中所有的完整数字:7, 903, 123, 45, 67。
如果只用单个字符类\d(匹配任意一个数字),配合g标志会得到 11 个单独的数字,而不是 5 个完整数字。原因在于:一个"数字"本质上是由 1 个或多个数字字符组成的连续序列。
要表达"1 个或多个",就需要在\d后面附加一个量词:
let str = "+7(903)-123-45-67"; let numbers = str.match(/\d{1,}/g); alert(numbers); // 7,903,123,45,67量词的作用对象不限于单个字符,它可以附加在字符、字符类(如\d)或字符集合(如[a-z])之后,统一指定"需要出现多少次"。这正是本专题 09-regexp-quantifiers/article.md 的核心主题。
精确计数:{n}、{n,m}与{n,}
最简单的量词是写在花括号里的数字{n},它给出三种形式。
精确次数{5}:恰好出现 N 次
\d{5}表示"恰好 5 个数字",与手写\d\d\d\d\d完全等价。下面的例子查找一个 5 位数字:
alert( "I'm 12345 years old".match(/\d{5}/) ); // "12345"如果不想匹配更长数字(比如 6 位、7 位),可以加上单词边界\b排除更长数字:\b\d{5}\b。关于\b的完整语义可参考专题 06-regexp-boundary。
次数范围{3,5}:匹配 3 到 5 次
把上下限都写进花括号,即可匹配 3~5 位数字:
alert( "I'm not 12, but 1234 years old".match(/\d{3,5}/) ); // "1234"注意:"I'm not 12..."中的12只有 2 位,不满足 3~5 的范围,因此被跳过;1234恰好 4 位,命中。
无上限{3,}:至少 3 次
可以省略上限:\d{3,}表示"长度 3 或更长的数字序列":
alert( "I'm not 12, but 345678 years old".match(/\d{3,}/) ); // "345678"回到电话号码的例子:一个数字是"一行中 1 个或多个数字组成的序列",所以正则就是\d{1,}:
let str = "+7(903)-123-45-67"; let numbers = str.match(/\d{1,}/g); alert(numbers); // 7,903,123,45,67三种形式的语义速查
| 写法 | 含义 | 等价手写 | 典型用途 |
|---|---|---|---|
{5} | 恰好 5 次 | \d\d\d\d\d | 邮编、定长编号 |
{3,5} | 3 到 5 次 | — | 长度受限的 ID |
{3,} | 至少 3 次,无上限 | — | 固定前缀的长序列 |
三个简写量词:+、?、*
最常用的三种量词有专门的简写符号,理解它们的边界差异是写出正确正则的关键。
+:一个或多个(等价于{1,})
let str = "+7(903)-123-45-67"; alert( str.match(/\d+/g) ); // 7,903,123,45,67\d+与前面的\d{1,}效果完全一致,是提取"完整数字"最常用的写法。
?:零个或一个(等价于{0,1})
?让前面的符号变成可选。例如ou?r表示:o后面跟零个或一个u,再跟r。于是colou?r能同时匹配英式colour和美式color:
let str = "Should I write color or colour?"; alert( str.match(/colou?r/g) ); // color, colour*:零个或多个(等价于{0,})
*表示"可以重复任意次数,也可以完全不出现"。例如\d0*匹配"一个数字后跟任意数量的 0":
alert( "100 10 1".match(/\d0*/g) ); // 100, 10, 1与+对比会更直观——\d0+要求"至少一个 0",因此末尾没有 0 的1不会被匹配:
alert( "100 10 1".match(/\d0+/g) ); // 100, 10 // 1 not matched, as 0+ requires at least one zero三种简写一览
| 简写 | 含义 | 等价形式 | 记忆口诀 |
|---|---|---|---|
+ | 一个或多个 | {1,} | "至少一个" |
? | 零个或一个 | {0,1} | "可有可无" |
* | 零个或多个 | {0,} | "随便多少个" |
实战一:匹配十进制小数\d+\.\d+
量词是复杂正则的主要"积木",下面通过真实场景展示组合用法。
一个带小数点的数字(浮点数)可以描述为"整数部分 + 小数点 + 小数部分",各部分都是数字序列,因此正则写作\d+\.\d+。注意小数点.是特殊字符,必须用\.转义:
alert( "0 1 12.345 7890".match(/\d+\.\d+/g) ); // 12.345结果中0、1、7890因为缺少小数点和小数部分而被正确排除。
实战二:匹配无属性的开始 HTML 标签
第一版:/<[a-z]+>/i
<body>这类标签 =<+ 一个或多个拉丁字母 +>:
alert( "<body> ... </body>".match(/<[a-z]+>/gi) ); // <body>改进版:/<[a-z][a-z0-9]*>/i
HTML 规范允许标签名在非首位出现数字,例如<h1>。第一版[a-z]+无法匹配<h1>(因为h1以字母开头但1是数字)。改进方案:首位必须是字母[a-z],后续位置可以是字母或数字[a-z0-9]*:
alert( "<h1>Hi!</h1>".match(/<[a-z][a-z0-9]*>/gi) ); // <h1>注意这里*的妙用:[a-z0-9]*允许"零个或多个",使模式同时覆盖单字母标签<p>和带数字的标签<h1>。
实战三:匹配开始或结束 HTML 标签\/?
在上一个模式开头加上可选斜杠/?,就能同时匹配开始标签<h1>和结束标签</h1>:
alert( "<h1>Hi!</h1>".match(/<\/?[a-z][a-z0-9]*>/gi) ); // <h1>, </h1>关键细节:斜杠/是正则字面量的定界符,必须用反斜杠转义成\/,否则 JavaScript 会误以为它是模式结束符。
仓库练习印证:省略号与 HTML 颜色
本专题目录下内置了两个配套练习,正好覆盖{3,}与{6}的典型用法,可作为量词实战的验收题。
练习一:匹配省略号(3 个及以上连续点)
任务见 1-find-text-manydots/task.md:找出 3 个(或更多)连续的点号。
解答(见 1-find-text-manydots/solution.md):
let regexp = /\.{3,}/g; alert( "Hello!... How goes?.....".match(regexp) ); // ..., .....两个要点:
.是通配符特殊字符,必须先转义为\.才能匹配字面量点号;- 使用无上限形式
{3,}而非{3},才能把 5 个连续点的.....也完整匹配出来(若用{3},.....会被截成两个 3 点片段)。
练习二:匹配 6 位十六进制 HTML 颜色
任务见 2-find-html-colors-6hex/task.md:匹配#ABCDEF形式的颜色——先#,后接 6 个十六进制字符。
解答(见 2-find-html-colors-6hex/solution.md):
let regexp = /#[a-f0-9]{6}/gi; let str = "color:#121212; background-color:#AA00ef bad-colors:f#fddee #fd2"; alert( str.match(regexp) ); // #121212,#AA00ef十六进制字符集用[0-9a-fA-F]描述;若使用i标志忽略大小写,则可简写为[0-9a-f]。随后用精确量词{6}锁定恰好 6 位。
边界修正:/#[a-f0-9]{6}/gi会把 8 位字符串#12345678中的前 6 位#123456误判为颜色。解法是在末尾追加单词边界\b:
alert( "#123456".match( /#[a-f0-9]{6}\b/gi ) ); // #123456 alert( "#12345678".match( /#[a-f0-9]{6}\b/gi ) ); // null这个例子再次印证:量词控制"重复数量",而\b之类的锚点控制"匹配边界",两者配合才能得到精确结果。
精确与复杂度的权衡
从上面的 HTML 标签例子可以提炼出一条通用规律:正则越精确,通常就越长越复杂。
- 简单写法
<\w+>能匹配任意单词字符(字母、数字、下划线)构成的标签名,但也会误匹配<1a>这类 HTML 不允许的名字; - 严谨写法
<[a-z][a-z0-9]*>严格遵循 HTML 标签命名规范(首位必须字母),更可靠。
实际项目中两种写法都可以接受,选择取决于:你对"多余匹配"的容忍度有多高,以及能否通过其他手段(如后续过滤)轻松剔除误报。这是正则设计中最常见的权衡取舍,也是 09-regexp-quantifiers/article.md 特别强调的经验法则。
延伸阅读:量词的贪心行为
掌握了量词的"数量语义"后,还须了解它的匹配行为。默认情况下所有量词都是**贪婪(greedy)**的:引擎会尽可能多地匹配字符,直到无法继续为止。例如".+"在a "witch" and her "broom" is one中会一口气匹配到最后一个引号,得到"witch" and her "broom"而非两个独立引号片段。这种"贪心"行为及其解决方案(懒惰量词+?、*?、??)详见下一篇专题 10-regexp-greedy-and-lazy。
此外,本专题在正则系列中的位置位于字符类(02-regexp-character-classes)、锚点与边界(04-regexp-anchors、06-regexp-boundary)之后,建议按顺序阅读以建立完整的正则知识链。通过 9-regular-expressions 的目录索引可以浏览全部正则专题。
小结
- 精确量词
{n}、{n,m}、{n,}分别对应"恰好 n 次""n 到 m 次""至少 n 次"; - 简写
+(一个或多个)、?(零个或一个)、*(零个或多个)覆盖了绝大多数日常需求; - 量词可以叠加在字符类(
\d、[a-z])上组合出完整模式,如小数\d+\.\d+、HTML 标签<\/?[a-z][a-z0-9]*>; - 转义(
\.、\/)与边界锚点(\b)是量词之外必备的精确化工具; - 越精确的正则越复杂,实际选择取决于对误报的容忍度;
- 默认量词是贪婪的,行为细节请继续学习贪心与懒惰量词专题。
- 文档/教程
- 前端
【免费下载链接】en.javascript.info
Modern JavaScript Tutorial
相关推荐
Modern JavaScript Tutorial:用正则精确匹配 HTML 标签——贪婪、懒惰量词与 `[^<>]` 排除法实战
Modern JavaScript Tutorial:用正则精确匹配 HTML 标签——贪婪、懒惰量词与 ^< 排除法实战 本篇基于 Modern JavaSc
文档/教程前端JavaScript 正则交替实战:用 `<style(>|\s.*?>)` 精确匹配完整 HTML 标签
JavaScript 正则交替实战:用 <style |\s. ? 精确匹配完整 HTML 标签 正则表达式中的"交替(Alternation)"(用 | 表示
文档/教程前端JavaScript 正则 Sticky 标志 `y`:精确位置匹配与 lastIndex 深入指南
JavaScript 正则 Sticky 标志 y :精确位置匹配与 lastIndex 深入指南 Sticky 标志 y ( pattern:y )让正则表达
文档/教程前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考