☰
JavaScript 正则量词完全指南:+、*、? 与 {n} 实现精确匹配
2026/10/8 13:34:03 网站建设 项目流程
  • 文档/教程
  • 前端

【免费下载链接】en.javascript.info

Modern JavaScript Tutorial

项目地址:https://gitcode.com/gh_mirrors/en/en.javascript.info
点击查看免费下载

正则表达式中的量词(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

项目地址:https://gitcode.com/gh_mirrors/en/en.javascript.info
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询