news 2026/10/24 1:42:08

正则表达式量词完全指南:`+`、`*`、`?` 与 `{n}` 的匹配次数控制(zh.javascript.info)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
正则表达式量词完全指南:`+`、`*`、`?` 与 `{n}` 的匹配次数控制(zh.javascript.info)
  • 文档
  • 教程
  • 前端

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

现代 JavaScript 教程(The Modern JavaScript Tutorial),以最新的 ECMAScript 规范为基准,通过简单但足够详细的内容,为你讲解从基础到高阶的 JavaScript 相关知识。

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

导读

本文围绕现代 JavaScript 教程仓库中的「量词」章节,系统讲解正则表达式中控制匹配次数的核心语法:精确数量{n}、范围{n,m}以及常用缩写+、*、?。你将学会用量词把零散的字符类组装成能匹配电话号码、小数、HTML 标签、颜色值等真实文本的模式,并通过仓库内配套的实战任务与相邻章节(字符类、词边界、贪婪/惰性量词)掌握量词在不同场景下的行为与取舍。读完本文,你不仅能写出/\d{1,}/g、/colou?r/g这类常见表达式,还能理解"更精确的正则往往更复杂"这一设计准则。

量词解决了什么问题

假设我们拿到一个字符串+7(903)-123-45-67,想从中提取出所有完整的数字:7, 903, 123, 45, 67。如果只用单个字符类\d,配合g修饰符,得到的是一个个孤立的数字字符,而不是"完整的数":

let str = "+7(903)-123-45-67"; alert(str.match(/\d/g)); // 7,9,0,3,1,2,3,4,5,6,7

问题在于:一个"数"是一个或多个数字的连续序列。要表达"出现多少次",就需要在字符(或字符类、[...]集合)后面附加一个量词(quantifier)。这正是本仓库 09-regexp-quantifiers/article.md 一章的主题,也是后续正则实战的基础模块。

精确数量:{n}与{n,m}

确切位数{5}

最简单的量词是写在花括号里的数字{n},它表示前面那个字符(或字符类)恰好出现 n 次。

alert("I'm 12345 years old".match(/\d{5}/)); // "12345"

\d{5}与手写五个\d\d\d\d\d完全等价。如果要排除位数更多的数字(比如123456中的前五位),可以借助词边界\b,写成\b\d{5}\b,只匹配独立成词的 5 位数。

范围{3,5}与省略上限的{3,}

在花括号中写入下限和上限,即可表达范围:

alert("I'm not 12, but 1234 years old".match(/\d{3,5}/)); // "1234"
  • \d{3,5}匹配 3 到 5 位数字;
  • \d{3,}省略上限,表示"至少 3 位"(本例匹配345678);
  • 对照{3,5}可以发现,12只有两位所以不匹配,1234恰好落在范围内。

回到电话示例,用\d{1,}表达"一个及以上数字"即可一次性取出全部数字:

let str = "+7(903)-123-45-67"; let numbers = str.match(/\d{1,}/g); alert(numbers); // 7,903,123,45,67

量词还可以作用在字符类之外的字符或集合上,例如\.{3,}表示"连续 3 个及以上点号",这在仓库配套任务 1-find-text-manydots/task.md 中被用于查找省略号(连续 3 个或更多.)。注意点号.是特殊字符,必须转义为\.,其标准解法参见 1-find-text-manydots/solution.md:

let regexp = /\.{3,}/g; alert("Hello!... How goes?.....".match(regexp)); // ..., .....

三种常用缩写:+、?、*

日常使用中,几个高频量词有专门缩写,与{n}形式完全等价:

缩写含义等价写法典型示例
+一个或多个{1,}\d+匹配所有连续数字
?零个或一个(可选){0,1}ou?r同时匹配or与our
*零个及以上{0,}\d0*匹配数字后跟任意数量(含零个)的0

+:一个或多个

\d+等价于\d{1,},直接从电话号码字符串中取出全部数字:

let str = "+7(903)-123-45-67"; alert(str.match(/\d+/g)); // 7,903,123,45,67

?:零个或一个(使符号可选)

?让前面的字符"可有可无"。模式ou?r表示:匹配o,后跟零个或一个u,再跟r。于是colou?r能同时匹配美式拼写与英式拼写:

let str = "Should I write color or colour?"; alert(str.match(/colou?r/g)); // color, colour

*:零个及以上

\d0*匹配"一个数字后面跟着任意数量的零(可能很多,也可能一个都没有)":

alert("100 10 1".match(/\d0*/g)); // 100, 10, 1

与+对比更能看出差异:\d0+要求至少有一个零,因此1不会被匹配出来:

alert("100 10 1".match(/\d0+/g)); // 100, 10("1" 被排除)

量词实战:从数字到 HTML 标签

量词是构造复杂正则的主要"积木"。仓库章节 09-regexp-quantifiers/article.md 提供了三个递进示例,展示量词与字符类、转义、可选符号的组合能力。

小数的正则表达式:\d+\.\d+

带浮点的小数由"整数部分 + 点 + 小数部分"组成,于是写成\d+\.\d+(点号需转义):

alert("0 1 12.345 7890".match(/\d+\.\d+/g)); // 12.345

整数和小数部分都要求至少一位数字,所以0、1、7890均被排除,只有12.345命中。

无特性的开放 HTML 标签:从<[a-z]+>到<[a-z][a-z0-9]*>

第一步,最简单的写法是/<[a-z]+>/i:字符<后跟一个或多个拉丁字母,再跟>:

alert("<body> ... </body>".match(/<[a-z]+>/gi)); // <body>

但根据 HTML 标准,标签名从第二个字符起可以出现数字(例如<h1>),[a-z]+无法覆盖这种情况。因此进阶版用[a-z][a-z0-9]*:首字符必须是字母,后续可以是字母或数字,且数量为零个或多个:

alert("<h1>Hi!</h1>".match(/<[a-z][a-z0-9]*>/gi)); // <h1>

这里*的"零个及以上"语义正是关键——单字母标签名(如<p>)在[a-z]之后可以没有更多字符。

同时匹配开标签与闭标签:/<\/?[a-z][a-z0-9]*>/i

在模式开头加入可选的斜杠/,即可让同一个正则同时匹配<h1>与</h1>:

alert("<h1>Hi!</h1>".match(/<\/?[a-z][a-z0-9]*>/gi)); // <h1>, </h1>

注意斜杠必须写成\/:在 JavaScript 的字面量正则pattern:/.../中,未转义的/会被引擎当作模式的结束符。关于特殊字符转义的完整规则,可参考仓库的 07-regexp-escaping/article.md(其中同样说明了使用new RegExp(...)构造时不必转义斜杠)。

精确与复杂之间的权衡

从上述例子能总结出一条通用规律(原文档以 smart 提示框给出):正则表达式越精确,往往就越长越复杂。例如 HTML 标签可以偷懒写成<\w+>,但由于 HTML 对标签名的限制更严格(首字符必须是字母),<[a-z][a-z0-9]*>更可靠。实际开发中两种变体都可接受,具体取舍取决于你对"额外误匹配"的容忍度,以及事后用其他手段剔除误匹配的难易程度。

量词与词边界配合:匹配 HTML 颜色值

仓库配套任务 2-find-html-colors-6hex/task.md 要求匹配#ABCDEF形式的颜色值:#后紧跟六位十六进制字符。利用字符类[a-f0-9]配合精确量词{6}与i修饰符,可得到/#[a-f0-9]{6}/gi:

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

但该解法存在一个边界问题:它会从更长的序列#12345678中切出前六位#123456。标准解法(见 2-find-html-colors-6hex/solution.md)是在末尾追加词边界\b,确保颜色值后面紧邻的不是单词字符:

// 合法颜色值 alert("#123456".match(/#[a-f0-9]{6}\b/gi)); // #123456 // 不是颜色值(后面还跟着数字) alert("#12345678".match(/#[a-f0-9]{6}\b/gi)); // null

\b是一种零宽检查:它在字符串开头(首字符为单词字符时)、单词字符与非单词字符之间、以及字符串末尾(末字符为单词字符时)成立。注意\w只包含拉丁字母、数字与下划线,因此\b对西里尔字母、中文等非拉丁文本并不适用——详见仓库 06-regexp-boundary/article.md。\d、\w、\s等字符类及其大写反向类(\D、\W、\S)的定义见 02-regexp-character-classes/article.md。

量词的两种工作模式:贪婪与惰性

量词还有一层容易被忽略的关键语义:默认(贪婪)情况下,量词会尽可能多地匹配字符。例如/\d+/会吃掉所有连续数字;用/".+"/去匹配a "witch" and her "broom" is one,得到的不是两个引号片段,而是从第一个引号一直吞到最后一个引号的"witch" and her "broom"。

仓库在 10-regexp-greedy-and-lazy/article.md 中用"女巫与扫帚"的例子完整演示了引擎的贪婪搜索与回溯过程:点.一路匹配到字符串末尾,发现剩余模式(引号)无法匹配后,再逐步"吐出"字符(回溯)直到找到可行的结束位置。

在量词后追加一个?即可切换为惰性模式,如*?、+?、??,表示"重复尽可能少的次数":

let regexp = /".+?"/g; let str = 'a "witch" and her "broom" is one'; alert(str.match(regexp)); // "witch", "broom"

这里问号?的双重身份值得注意:单独使用时它是"零或一个"的量词,而跟在另一个量词(甚至它自己??)后面时,它把匹配模式从贪婪切换为惰性。惰性并非万能药——文中还演示了/<a href=".*?" class="doc">/g在处理...<a href="link1" class="wrong">... <p style="" class="doc">...时仍会错误跨标签匹配,最终的正确方案是改用排除字符集href="[^"]*",用"非引号"集合精确限定取值范围。这再次印证了同一原则:写出精确的正则,往往需要组合量词、字符类与边界检查,而不是一味依赖某种单一技巧。

总结

量词是正则表达式的核心"乘法表",本文覆盖了仓库 09-regexp-quantifiers 章节的全部要点:

  • 精确数量:{n}恰好 n 次、{n,m}n 到 m 次、{n,}至少 n 次;
  • 缩写:+(一个及以上,{1,})、?(零或一个,{0,1})、*(零个及以上,{0,});
  • 组合实战:\d+\.\d+匹配小数、<[a-z][a-z0-9]*>匹配 HTML 标签、<\/?...>同时匹配开闭标签、#[a-f0-9]{6}\b匹配颜色值;
  • 配套任务验证:\.{3,}查找省略号、#[a-f0-9]{6}\b精确匹配六位颜色值,两个任务的题目与标准解分别位于 1-find-text-manydots 与 2-find-html-colors-6hex 目录;
  • 深层语义:默认贪婪、加?变惰性,精确性往往以表达式复杂度为代价。

掌握量词之后,建议继续阅读仓库的 10-regexp-greedy-and-lazy/article.md 理解回溯行为,并结合 11-regexp-groups/article.md 等后续章节,把量词与分组、捕获结合使用,构建完整的实战正则能力。

  • 文档
  • 教程
  • 前端

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

现代 JavaScript 教程(The Modern JavaScript Tutorial),以最新的 ECMAScript 规范为基准,通过简单但足够详细的内容,为你讲解从基础到高阶的 JavaScript 相关知识。

项目地址:https://gitcode.com/gh_mirrors/zh/zh.javascript.info
点击查看免费下载
上一篇:Open Design 设计系统实践:还原 Duolingo 游戏化视觉语言的完整指南
下一篇:三月七小助手:星穹铁道自动化工具如何帮你每天节省30分钟游戏时间

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/24 1:41:29

AI原生开发工具链:Superpowers概念解析与四大组件协同实践

1. “Superpowers”不是超能力&#xff0c;是开发者工具链的智能增强层最近在好几个技术社区里&#xff0c;看到越来越多开发者在问“superpowers 怎么装”“cursor superpowers 开启不了”“antigravity 和 superpowers 是什么关系”。这词儿听着像漫威电影里的设定&#xff0…

作者头像 李华
网站建设 2026/10/16 13:45:27

题解:洛谷 P9946 [USACO20JAN] Word Processor B(废)

本文分享的必刷题目是从蓝桥云课、洛谷、AcWing等知名刷题平台精心挑选而来,并结合各平台提供的算法标签和难度等级进行了系统分类。题目涵盖了从基础到进阶的多种算法和数据结构,旨在为不同阶段的编程学习者提供一条清晰、平稳的学习提升路径。 欢迎大家订阅我的专栏:算法…

作者头像 李华
网站建设 2026/10/15 6:06:27

阿里云CentOS 7仓库配置

# 下载阿里云CentOS 7仓库配置 sudo curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo # 替换变量 sudo sed -i s/\$releasever/7/g /etc/yum.repos.d/CentOS-Base.repo # 更新缓存 sudo yum clean all && sudo yum makeca…

作者头像 李华
网站建设 2026/10/16 0:37:33

软考系统架构师:关键知识点

架构设计质量属性性能&#xff1a;系统响应时间、吞吐量&#xff08;如每秒处理事务数&#xff09;。可用性&#xff1a;系统正常运行时间的比例&#xff08;如 99.99%&#xff09;。安全性&#xff1a;抵御攻击、数据保密性及完整性。可修改性&#xff1a;变更成本的控制&…

作者头像 李华
网站建设 2026/10/13 23:43:27

Keil工程在h文件中定义变量

Keil工程在h文件中定义变量 1. 背景 关于变量的定义&#xff0c;严谨的做法当然是在c文件中定义&#xff0c;h文件中声明。但总有人喜欢在h文件中定义全局变量&#xff0c;可能是喜欢集中管理全局变量&#xff0c;也可能是觉得一个变量要维护c和h两个地方太麻烦&#xff0c;总之…

作者头像 李华
网站建设 2026/10/15 22:37:41

蒙眼下山:梯度下降的AI智慧

假设你站在一座山上&#xff0c;四周大雾&#xff0c;看不清山谷在哪里。 你的目标是&#xff1a;尽可能走到更低的位置。 虽然看不到整座山&#xff0c;但你可以感受脚下的坡度&#xff1a; 哪边上坡最陡&#xff1f;↓ 朝它的反方向走一小步↓ 重新判断坡度↓ 继续往下走这就…

作者头像 李华