- 教程
- 文档
- 示例工程
【免费下载链接】website-archive
Archive of the Coding Train website (first version)
本文基于 website-archive 仓库中《Programming with Text》课程第 2.6 节文档(_learning/programming-with-text/2.6-test-and-match.md)展开,结合其配套源码示例(Courses/programming_with_text/session02/2-0607_regexTestMatchExec),系统讲解正则表达式与字面量字符串的区别,以及 JavaScript 中两个最常用的正则方法
test()和match()的用法、返回值与实战陷阱。读完本文,你将掌握如何在 p5.js / 浏览器环境中用正则表达式校验文本、提取匹配结果,并理解它与exec()、split()、replace()等方法的配合关系。
一、背景:正则表达式在《Programming with Text》课程中的位置
本仓库是 Coding Train 网站第一版的归档仓库,其中 Courses/programming_with_text 目录对应"Programming with Text / Programming from A to Z"课程。本课(第 2.6 节,视频W7S_Vmq0GSs)属于第 2 章"正则表达式(Regular Expressions)",该章的文档骨架位于 _learning/programming-with-text/index.md 与 _learning/programming-with-text/2.1-introduction.md:
- 2.1 正则表达式入门(什么是正则、如何使用);
- 2.2 元字符(meta-characters);
- 2.3 字符类(character classes);
- 2.4 捕获分组(capturing groups);
- 2.5 反向引用(back references);
- 2.6
test()与match()(本文主题); - 2.7
exec(); - 2.8
split(); - 2.9
replace()。
本节文档的核心命题很明确:在 JavaScript 中,正则表达式与普通字面量字符串是两种不同的东西,而test()与match()是入门的两个关键函数——一个用来"判断是否匹配",一个用来"取出匹配结果"。
二、正则表达式 vs. 字面量字符串:先厘清概念
在 JavaScript 中,一段文本既可以写成普通字符串,也可以写成正则表达式:
// 普通字符串字面量:它表示文本本身 var str = "hello"; // 正则表达式字面量:它表示一种"模式",用于在文本中查找/匹配 var regex = /hello/;二者的本质区别在于:
| 维度 | 字面量字符串 | 正则表达式 |
|---|---|---|
| 本质 | 一段确定不变的文本 | 一种描述"字符模式"的规则 |
| 运算 | 只能做indexOf、includes、split等文本操作 | 可通过test、match、exec、replace等方法做模式匹配 |
| 特殊字符 | \、\n等转义符按字面意义处理 | 元字符如.、*、+、()、[]具有模式语义 |
| 典型用途 | 保存/拼接/展示文本 | 校验格式、查找提取、批量替换 |
正则表达式字面量由两个正斜杠包裹,模式写在其中,末尾可以追加标志位(flags),例如:
var r = /(\d{3})[-.]\d{4}/g; // g = global,全局匹配这个例子同时用到了:
\d:匹配任意数字(0–9);{3}、{4}:量词,分别表示前面元素恰好出现 3 次、4 次;[-.]:字符类,匹配-或.中的一个;(...):捕获分组,把匹配到的内容"圈"出来,稍后可通过编号引用;g:全局标志,让匹配从"找第一个"变为"找所有"。
三、test():只关心"有没有匹配"
test()是RegExp对象的方法,返回布尔值——只回答"这段文本里有没有匹配到该模式",不返回匹配到的具体内容:
var r = /(\d{3})[-.]\d{4}/; r.test("111-2222"); // true,模式匹配成功 r.test("hello world"); // false,模式不匹配test()的使用场景非常典型:校验输入是否符合格式,比如表单中的电话号码、邮箱、日期校验。它不关心匹配内容是什么,只给一个 true/false 的判断结果,因此代码意图清晰、性能开销小。
四、match():取出匹配结果
match()是String对象的方法,返回匹配结果。它的返回值受是否带g标志影响很大,这是新手最容易踩的坑:
4.1 不带g:返回第一个完整匹配 + 捕获分组
var s = "Here is are two numbers 111-2222 and 444-5555"; var r = /(\d{3})[-.]\d{4}/; // 没有 g var result = s.match(r); // result[0] -> 完整匹配:"111-2222" // result[1] -> 第 1 个捕获分组:"111" // result.index -> 匹配开始的位置 // result.input -> 原始字符串不带g时,match()返回一个类数组对象,result[0]是完整匹配,result[1]、result[2]…依次对应各捕获分组,同时带有index和input属性。
4.2 带g:返回所有完整匹配,但丢弃捕获分组
var r = /(\d{3})[-.]\d{4}/g; // 带 g var result = s.match(r); // result -> ["111-2222", "444-5555"]带g时,match()返回一个普通数组,里面是所有完整匹配的文本;但此时捕获分组的信息会被丢弃(result[1]不再有意义)。
这个限制正是课程引入exec()的原因——如果想"全局匹配 + 保留捕获分组",就要用exec()配合while循环。
五、实战示例:配套仓库源码逐行拆解
本节的配套示例仓库为 Courses/programming_with_text/session02/2-0607_regexTestMatchExec,包含两个文件:index.html(页面结构)与sketch.js(逻辑)。
5.1 页面结构(index.html)
index.html 中:
- 通过 CDN 引入
p5.min.js(版本1.4.1); - 提供一个
<textarea id="input">,默认内容是示例文本"Here is are two numbers 111-2222 and 444-5555"; - 提供一个
submit按钮和<p id="output">输出区域。
<textarea cols=50 id="input">Here is are two numbers 111-2222 and 444-5555</textarea> <p><button id="submit">submit</button></p>5.2 核心逻辑(sketch.js)
sketch.js 完整代码如下:
var textfield; var output; var submit; function setup() { noCanvas(); textfield = select('#input'); output = select('#output'); submit = select('#submit'); submit.mousePressed(newText); } function newText() { var s = textfield.value(); var r = /(\d{3})[-.]\d{4}/g; // var matches = s.match(r); // var result = r.exec(s); var results; while ((results = r.exec(s))) { createP(results[1]); // do something with the matched results } }这段代码是本节教学内容的直接落地,几个要点:
select()与mousePressed():使用 p5.dom 的辅助方法选取页面元素、绑定按钮点击事件;- 模式
/(\d{3})[-.]\d{4}/g:匹配"3 位数字 +-或.+ 4 位数字"的电话号码模式,其中(\d{3})是捕获分组(区号部分),[-.]允许分隔符为连字符或点号; - 被注释掉的两种写法:
s.match(r)与r.exec(s)是课程中对比过的替代方案,最终采用了exec()循环——因为需要全局匹配并且读取捕获分组results[1]; while ((results = r.exec(s)))循环:每次迭代exec()返回一个匹配结果对象(数组形式),results[1]就是每组电话号码的区号"111"、"444";当没有更多匹配时exec()返回null,循环自然结束。
运行效果:点击 submit 后,页面下方会逐行输出从文本中提取到的所有区号。
六、exec():match()的"全局 + 分组"替代方案
本节的配套仓库与第 2.7 节(_learning/programming-with-text/2.7-exec.md)是同一个仓库(front matter 中repository均为/Courses/programming_with_text/session02/2-0607_regexTestMatchExec),这说明test()/match()/exec()在本课程中被设计为一组连贯的教学主题。
exec()是RegExp对象的方法,与match()的关键差异:
| 方法 | 所属对象 | 带g时的行为 | 捕获分组 |
|---|---|---|---|
match() | String | 返回所有完整匹配的数组 | 丢弃 |
exec() | RegExp | 每次调用返回一个匹配(含分组),通过lastIndex记住进度 | 保留 |
var r = /(\d{3})[-.]\d{4}/g; var result; while ((result = r.exec(s)) !== null) { console.log(result[0]); // 完整匹配 console.log(result[1]); // 捕获分组 }exec()是有状态的:带g时它会更新正则对象的lastIndex属性,下一次调用从上次匹配结束的位置继续搜索;当搜索到末尾返回null后,lastIndex会被重置为 0。因此:
- 反复调用同一个
exec()前要确认lastIndex的状态; - 在
while循环中务必把exec()的返回值赋给变量再判断,避免重复调用导致死循环或跳步。
这也是 2.6 文档与 2.7 文档共享同一份源码示例的原因:源码 sketch.js 中同时保留了match()与exec()两种写法的注释,正是为了直观对比二者差异。
七、易错点与最佳实践
7.1g标志对match()返回值的决定性影响
- 无
g:返回完整匹配 + 所有捕获分组(含index、input属性); - 有
g:只返回所有完整匹配的数组,分组丢失。
需要同时"拿到全部匹配 + 分组"时,请改用exec()循环,而不是match()。
7.2test()与g标志的隐藏状态
带g的test()同样会推进lastIndex,导致同一个正则多次调用test()的结果在 true/false 之间交替。用test()做布尔判断时,通常不要加g标志。
7.3 用分组提取结构化信息
本例用(\d{3})捕获区号,是"模式匹配 + 数据提取"的典型组合。结合本系列前序内容:
- 分组语法与引用方式见 _learning/programming-with-text/2.4-capturing-groups.md;
- 用
\1反向引用已匹配分组的用法见 _learning/programming-with-text/2.5-back-references.md。
7.4 与split()、replace()串联使用
正则匹配只是文本处理的第一步。本系列后续两节展示了正则的另外两个高频入口:
split():按正则分隔符把文本切成 token,示例见 2-08_regexSplit/sketch.js(var r = /(\W+)/; var words = s.split(r);),配套文档 _learning/programming-with-text/2.8-split.md;replace():用正则做查找替换,回调函数replacer(match, group1, group2)可拿到每个捕获分组,示例见 2-09_regexReplace/sketch.js,配套文档 _learning/programming-with-text/2.9-replace.md。
八、总结:test()/match()/exec()怎么选
| 需求 | 推荐方法 |
|---|---|
| 只判断文本是否符合模式(校验) | regex.test(str),不加g |
| 取第一个匹配及捕获分组 | str.match(regex),不加g |
| 取所有完整匹配,不需要分组 | str.match(regex),加g |
| 取所有匹配且需要捕获分组 | while ((m = regex.exec(str)))循环 |
本节文档(_learning/programming-with-text/2.6-test-and-match.md)虽然篇幅精炼,但传递的是正则入门最关键的分水岭:先分清"字面量字符串"与"正则模式",再分清test()(判断)与match()(提取)。配合仓库中2-0607_regexTestMatchExec的完整可运行示例,你可以在浏览器中直接打开index.html实验:输入任意包含111-2222、444.5555之类片段的文本,点击 submit 即可看到exec()循环逐条提取区号的过程,从而直观理解三个方法的差异。
进一步学习,可继续阅读本系列的 2.7exec()、2.8split()与 2.9replace(),它们共同构成 JavaScript 正则处理的完整工具箱。
- 教程
- 文档
- 示例工程
【免费下载链接】website-archive
Archive of the Coding Train website (first version)
相关推荐
现代 JavaScript 教程:正则表达式与字符串方法(match / matchAll / replace / exec / test 全解析)
现代 JavaScript 教程:正则表达式与字符串方法(match / matchAll / replace / exec / test 全解析) 导读 在
文档教程SublimeREPL:在Sublime Text中打造无缝交互式编程环境的终极解决方案
SublimeREPL:在Sublime Text中打造无缝交互式编程环境的终极解决方案 SublimeREPL是一款革命性的Sublime Text插件,它将
开发工具代码编辑器JavaScript 正则表达式方法详解
JavaScript 正则表达式方法详解 正则表达式是 JavaScript 中处理字符串的强大工具,本文将全面介绍 JavaScript 中与正则表达式相关的
文档教程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考