- 文档
- 教程
- 前端
【免费下载链接】zh.javascript.info
现代 JavaScript 教程(The Modern JavaScript Tutorial),以最新的 ECMAScript 规范为基准,通过简单但足够详细的内容,为你讲解从基础到高阶的 JavaScript 相关知识。
本文基于《现代 JavaScript 教程(zh.javascript.info)》中「找出所有数字」这一经典练习,从题目要求出发,逐步拆解正则表达式
/-?\d+(\.\d+)?/g的每个组成部分:字符类、量词、点号转义、可选负号与捕获组。结合仓库中 字符类、量词 与 捕获组 章节的讲解,以及同一章节内其他练习对该模式的复用,深入说明其原理、边界情况与实战扩展,帮助你掌握"一次性匹配整数、浮点数和负数"这类真实文本解析需求的标准写法。
1. 题目回顾:找出字符串中的所有十进制数字
练习 03-find-decimal-numbers/task.md 的要求非常明确:
编写一个正则表达式,找出所有十进制数字,包括整数、浮点数和负数。
给定的用例字符串与期望输出:
let regexp = /你的正则表达式/g; let str = "-1.5 0 2 -123.4."; alert( str.match(regexp) ); // -1.5, 0, 2, -123.4注意这里的三个隐含要求:
- 整数:如
0、2,没有小数点; - 浮点数:如
-1.5、-123.4,带小数部分; - 负数:如
-1.5、-123.4,以负号开头; - 字符串末尾有一个孤立的小数点(
-123.4.中的最后一个.),它不属于任何数字,不应被匹配。
题目刻意把这个"孤立点"放在用例里,就是考察你对"点号必须转义、且小数部分必须至少有一位数字"这一细节的理解。
2. 标准答案与逐步拆解
练习的标准解答 03-find-decimal-numbers/solution.md 给出了简洁优雅的模式:
let regexp = /-?\d+(\.\d+)?/g; let str = "-1.5 0 2 -123.4."; alert( str.match(regexp) ); // -1.5, 0, 2, -123.4这个模式可以拆成四个逻辑部件,逐段理解:
| 模式片段 | 含义 | 出处 |
|---|---|---|
-? | 可选的负号(零个或一个-) | 量词?等价于{0,1} |
\d+ | 一个或多个数字,即整数部分 | 字符类\d+ 量词+ |
\. | 转义的点号,匹配字面意义上的小数点 | 点在正则中需转义 |
(\d+)? | 可选的"点后数字",整体作为一个单位 | 捕获组 + 量词? |
2.1\d+:匹配整数部分
\d是 JavaScript 正则中的数字字符类,匹配从0到9的任意一位数字,这一点在 字符类 一章中有详细说明。单独一个\d只能匹配一位数字,加上量词+(等价于{1,},表示"一个或多个")之后,\d+就能匹配任意长度的整数序列。
在 量词 章节中同样可以看到这样的基础用法:
let str = "+7(903)-123-45-67"; alert( str.match(/\d+/g) ); // 7,903,123,45,67这正是"数字序列"的标准写法。
2.2\.:小数点必须转义
在正则表达式中,点号.是一个特殊字符类,匹配"除换行符之外的任意字符"(见 字符类 的"点匹配任何字符"一节)。因此如果要匹配字面意义上的小数点,必须写作\.,否则\d+.\d+会错误地匹配像1x5这样中间夹着任意字符的内容。
对比一下 量词 章节中给出的"浮点数"初版模式:
alert( "0 1 12.345 7890".match(/\d+\.\d+/g) ); // 12.345\d+\.\d+能匹配12.345,但它强制要求小数部分存在,无法匹配整数0或2——这正是本练习需要在它基础上扩展的原因。
2.3(\d+)?:捕获组让小数部分整体可选
把\.\d+用括号括起来并加上?,即(\.\d+)?,含义是"小数点加数字序列这个整体,出现零次或一次"。这正是 捕获组 章节强调的两个作用之一:
如果我们将量词放在括号后,则它将括号视为一个整体。
如果不加括号写成\.\d+?,?只会作用于紧邻的\d,语义完全不同。括号在这里的作用是改变量词的作用范围,把"点号 + 数字"绑定成一个不可分割的单位。
2.4-?:可选负号
模式最开头的-?用量词?表示"零个或一个负号",使得正数与负数都能被匹配,同时不会要求每个数字都带负号。
3. 匹配过程与结果验证
对字符串"-1.5 0 2 -1234."运行/-?\d+(\.\d+)?/g,正则引擎从左到右扫描:
-1.5:-匹配可选负号,1匹配\d+,.5匹配(\.\d+)?→ 完整匹配-1.5;0:无负号,0匹配\d+,小数部分缺失 → 匹配0;2:同理匹配2;-1234:匹配-1234,此时(\.\d+)?是可选的,引擎尝试匹配末尾的.,但后面没有数字,\.\d+无法成立,于是放弃小数部分 → 匹配-1234;- 末尾孤立的
.被跳过,因为\.必须紧跟至少一位数字才能构成小数部分。
最终str.match(regexp)返回数组["-1.5", "0", "2", "-1234"],与题目期望完全一致。
值得注意的一个细节是:当正则带有g修饰符时,str.match返回的是所有完整匹配项组成的数组,不会包含捕获组的内容。这一点在 捕获组 的"带有组搜索所有匹配项:matchAll"一节中有明确说明。如果你不仅需要匹配到的数字本身,还需要提取"整数部分"和"小数部分"等组内内容,应当改用str.matchAll(regexp),它会为每个匹配项返回包含groups信息的完整数组。
4. 边界情况与潜在陷阱
4.1 不会匹配以点开头的小数
\d+强制要求小数点之前至少有一位数字,因此像.5这种省略整数部分的写法不会被匹配(只会匹配到其中的5)。如果业务场景需要支持这种形式,需要额外处理。
4.2 孤立小数点会被正确跳过
如题目用例-1234.末尾的.,因为\.\d+要求点后至少一位数字,孤立点无法构成小数部分,正则引擎会在整数部分结束后停止匹配,这正是标准答案的巧妙之处。
4.3 如需整词匹配可加\b
在纯数字提取场景下,-?\d+(\.\d+)?已经足够。但如果要避免从abc123def这类字符串中截取出123(例如验证一个字符串本身是否是合法数字),可以结合 锚点 章节介绍过的^...$或词边界\b来收紧匹配范围。同章节的 检查 MAC 地址练习 就展示了用^[0-9a-f]{2}(:[0-9a-f]{2}){5}$/i配合^...$进行整体校验的思路。
5. 同章节复用:这个模式是"表达式解析"的基础模块
这个十进制数字模式并非孤立练习——在同一个 捕获组 章节的 解析算术表达式练习 中,它被直接复用来解析形如"1.2 + 12"的算式:
let regexp = /(-?\d+(\.\d+)?)\s*([-+*\/])\s*(-?\d+(\.\d+)?)/;其解题说明中明确写道:"匹配数字的正则表达式:-?\d+(\.\d+)?,我们在上一题创建了这个表达式。"这说明本章节的练习设计是递进式的:先掌握"一个数字"的匹配,再把它嵌套进更大的模式,并用括号让每个部分(第一个数字、运算符、第二个数字)成为结果数组中的独立元素。
在 解析表达式练习 的完整解法中还展示了两个进阶技巧,与本主题直接相关:
- 用
(?:\.\d+)?这种非捕获组(见 捕获组 的"非捕获组 ?:"一节)排除不需要的小数部分结果,让result数组只保留真正关心的数字与运算符; - 用
result.shift()移除数组第 0 项(完整匹配),从而得到干净的操作数列表:
function parse(expr) { let regexp = /(-?\d+(?:\.\d+)?)\s*([-+*\/])\s*(-?\d+(?:\.\d+)?)/; let result = expr.match(regexp); if (!result) return []; result.shift(); return result; } alert( parse("-1.23 * 3.45") ); // -1.23, *, 3.45可以看到,本练习的-?\d+(\.\d+)?加上一层括号包装后,立刻变成了可复用的"数值 token"。
6. 从单题到体系:相关的正则知识点地图
围绕这个练习,可以把整个 正则表达式 章节的相关知识点串成一条学习路径:
| 知识点 | 章节 | 与本练习的关联 |
|---|---|---|
字符类\d | 字符类 | \d是数字匹配的基础 |
量词+、?、{n} | 量词 | +匹配多位数字,?让负号/小数部分可选 |
转义\. | 正则转义 | 让点号匹配字面小数点 |
捕获组(...) | 捕获组 | (\.\d+)?把小数部分绑定为一个整体 |
锚点^...$、词边界\b | 锚点、词边界 | 用于整体校验场景 |
matchAll与命名组 | 捕获组 | 提取每个匹配的内部结构 |
7. 总结
本练习的标准答案/-?\d+(\.\d+)?/g虽然只有短短一行,却浓缩了 JavaScript 正则中最核心的几个概念:
- 字符类
\d匹配数字; - 量词
+匹配"一个或多个",?让负号-?与小数部分(\.\d+)?变为可选; - 点号转义
\.保证匹配的是字面小数点; - 捕获组
(...)把"点号 + 数字"绑定成整体,从而允许对整个小数部分应用量词。
掌握这行模式之后,你就可以自然过渡到 解析算术表达式 这类更复杂的实战,以及 捕获组 章节中编号组、命名组、matchAll、替换引用$n/$<name>和(?:...)非捕获组等进阶能力,形成完整的正则实战知识闭环。
- 文档
- 教程
- 前端
【免费下载链接】zh.javascript.info
现代 JavaScript 教程(The Modern JavaScript Tutorial),以最新的 ECMAScript 规范为基准,通过简单但足够详细的内容,为你讲解从基础到高阶的 JavaScript 相关知识。
相关推荐
现代 JavaScript 教程正则实战:用捕获组一次性匹配整数、浮点数与负数
现代 JavaScript 教程正则实战:用捕获组一次性匹配整数、浮点数与负数 正则表达式的实战能力,往往体现在把"字符类、量词、捕获组"这些基础构件组合起来,
文档教程前端基于 en.javascript.info 的正则实战:用捕获组一步匹配全部十进制数字(整数、浮点数与负数)
基于 en.javascript.info 的正则实战:用捕获组一步匹配全部十进制数字(整数、浮点数与负数) 导读 在 JavaScript 中处理文本数据时,
文档/教程前端Modern JavaScript Tutorial 正则实战:用 `/-?\d+(\.\d+)?/` 匹配所有十进制数字(含负数与浮点数)
Modern JavaScript Tutorial 正则实战:用 / ?\d+ \.\d+ ?/ 匹配所有十进制数字(含负数与浮点数) 导读 在 JavaSc
文档/教程前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考