☰
website-archive 编程实战:JavaScript 正则表达式 `test()` 与 `match()` 方法详解
2026/10/14 15:56:29 网站建设 项目流程
  • 教程
  • 文档
  • 示例工程

【免费下载链接】website-archive

Archive of the Coding Train website (first version)

项目地址:https://gitcode.com/gh_mirrors/we/website-archive
点击查看免费下载

本文基于 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.6test()与match()(本文主题);
  • 2.7exec();
  • 2.8split();
  • 2.9replace()。

本节文档的核心命题很明确:在 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 } }

这段代码是本节教学内容的直接落地,几个要点:

  1. select()与mousePressed():使用 p5.dom 的辅助方法选取页面元素、绑定按钮点击事件;
  2. 模式/(\d{3})[-.]\d{4}/g:匹配"3 位数字 +-或.+ 4 位数字"的电话号码模式,其中(\d{3})是捕获分组(区号部分),[-.]允许分隔符为连字符或点号;
  3. 被注释掉的两种写法:s.match(r)与r.exec(s)是课程中对比过的替代方案,最终采用了exec()循环——因为需要全局匹配并且读取捕获分组results[1];
  4. 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)

项目地址:https://gitcode.com/gh_mirrors/we/website-archive
点击查看免费下载

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

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

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

立即咨询