- 文档
- 教程
- 前端
【免费下载链接】zh.javascript.info
现代 JavaScript 教程(The Modern JavaScript Tutorial),以最新的 ECMAScript 规范为基准,通过简单但足够详细的内容,为你讲解从基础到高阶的 JavaScript 相关知识。
导读
本文围绕现代 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 相关知识。
相关推荐
JavaScript 正则量词完全指南:+、*、? 与 {n} 实现精确匹配
JavaScript 正则量词完全指南:+、 、? 与 {n} 实现精确匹配 正则表达式中的量词(quantifier)是构建复杂匹配模式的核心"积木":它们决
文档/教程前端JavaScript 正则表达式中的量词详解:+, *, ? 和 {n}
JavaScript 正则表达式中的量词详解:+, , ? 和 {n} 引言 在 JavaScript 正则表达式中,量词 quantifiers 是极其重要的
文档教程前端JavaScript 正则表达式教程:量词 +, *, ? 和 {n} 的深入解析
JavaScript 正则表达式教程:量词 +, , ? 和 {n} 的深入解析 引言 在 JavaScript 正则表达式中,量词 quantifiers 是
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考