- 教程
- 文档
- 示例工程
【免费下载链接】website-archive
Archive of the Coding Train website (first version)
字符类(Character Classes)是正则表达式中“一次匹配一组字符中的任意一个”的核心语法,也是本仓库《Programming with Text(编程与文本)》课程正则表达式系列第 2.3 节的讲解主题。本文以该课程文档为主线,结合仓库内 session02 的正则表达式示例代码与若干 Coding Challenges 的实战源码,系统讲解[...]、区间、取反以及\d/\w/\s等速写类(shorthand classes)的用法、语义边界与常见误区,帮助你把这节课的知识直接落到可运行的 p5.js / JavaScript 项目中。
一、课程定位:2.3 在正则表达式系列中的位置
在 Programming with Text 系列索引 中,第 2 章以“正则表达式(Regular Expressions)”为专题,按视频编号依次展开:
- 2.1 正则表达式导论:介绍什么是正则表达式,并预告元字符、捕获括号、字符类以及
split()、match()、test()、replace()、exec()等 JavaScript 方法; - 2.2 元字符(Meta-characters):讨论元字符是什么以及在正则表达式中的角色;
- 2.3 字符类(Character Classes):本节课(本仓库文档 _learning/programming-with-text/2.3-character-classes.md)——讲解“在正则表达式中匹配一组字符中选择的任意一个”;
- 2.4 捕获组(Capturing Groups):讲解圆括号捕获组以及如何在查找/替换中引用编号分组;
- 2.5 反向引用(Back References)、2.6 test 与 match、2.7 exec、2.8 split、2.9 replace 则继续深入正则表达式在 JavaScript 中的实际应用。
因此,字符类不是孤立知识点:它是连接“元字符”(2.2)与“捕获组”(2.4)的桥梁,也是后续split、replace、test等章节大量复用的基础语法。
二、什么是字符类:一次匹配“一组字符中的任意一个”
课程 2.3 的定义非常精炼:字符类是一种在正则表达式中匹配一组字符中某一选择(a selection of characters)的方式。理解它的关键在“任意一个”三个字——字符类描述的不是“这一段必须是某个固定字符”,而是“这个位置允许出现集合内任一字符”。
最直观的写法是用方括号把候选字符括起来:
/[abc]/ // 匹配单个字符,它可以是 a、b 或 c 中的任意一个 /[aeiou]/ // 匹配任意一个元音字母与“或”运算符|的直觉不同,字符类处理的是单字符集合:[abc]等价于(a|b|c),但当候选集合较大或具有明确区间时,字符类要简洁得多。
字符类还可以直接嵌套进更复杂的模式,例如仓库 session02 的 test/match/exec 示例 中的电话号匹配模式:
var r = /(\d{3})[-.]\d{4}/g;这里的[-.]就是一个字符类:表示该位置可以是-(连字符)或.(点号)中的任意一个,因此111-2222与444.5555都能被匹配到——这正是课程配套 HTML 页面输入框中的示例文本(111-2222 and 444-5555)所验证的场景(见 2-0607 的 index.html)。
三、字符类语法速查表
| 写法 | 含义 | 等价说明 |
|---|---|---|
[abc] | 匹配 a、b、c 中任意一个字符 | 等价于(a\|b\|c) |
[a-z] | 匹配 a 到 z 区间内的任意小写字母 | 区间(range)写法,按字符编码顺序 |
[A-Z]、[0-9] | 匹配任意大写字母 / 任意数字 | 可组合为[A-Za-z0-9] |
[^abc] | 匹配除 a、b、c 之外的任意字符 | ^放在类内首位表示取反 |
\d | 匹配任意数字字符 | 等价于[0-9] |
\D | 匹配任意非数字字符 | 等价于[^0-9] |
\w | 匹配任意单词字符 | 通常等价于[A-Za-z0-9_](含下划线) |
\W | 匹配任意非单词字符 | 等价于[^A-Za-z0-9_] |
\s | 匹配任意空白字符 | 空格、制表符、换行等 |
\S | 匹配任意非空白字符 | 等价于[^\s] |
. | 匹配除换行外的任意字符 | 不属于严格字符类,但常与字符类对比理解 |
使用要点:
^取反:^只有在字符类内部且位于首位时才表示“排除”,例如[^0-9];若写成[0-9^],则^只是一个普通字面字符。- 连字符
-的语义:-在字符类中通常表示区间(如[a-z]);若想匹配字面意义的-,应放在类内末尾(如[-.]、[0-9-])或转义([\-])。 - 点号
.在类内是字面量:[-.]中的.不再匹配任意字符,而是一个普通点号——这是字符类最容易被忽视的“语法环境切换”特性。 - 速写类(shorthand)的本质:
\d、\w、\s本身就是预定义的字符类简写,因此\d与[0-9]等价;在需要“数字或连字符”这类混合集合时,手写[0-9-]比[\d-]更常见(多数引擎中两者等价,但手写区间可读性更好)。
四、仓库源码佐证:字符类在 Coding Train 示例中的真实用法
课程 2.3 文档本身是视频页(repository: false,无独立示例仓库),但同一章 session02 与后续 Coding Challenges 中保留了大量直接使用字符类的真实代码,正好用于验证与深化本节课的知识。
4.1 电话号匹配:[-.]字符类 +\d速写类
session02 的 2-0607 示例:
var r = /(\d{3})[-.]\d{4}/g; var results; while ((results = r.exec(s))) { createP(results[1]); }(\d{3}):捕获组,匹配三位数字;[-.]:字符类,允许分隔符为连字符或点号;\d{4}:匹配四位数字;- 全局标志
g配合exec()循环,可依次取出文本中的每一个匹配,而results[1]正是第一个捕获组(区号)的内容。
对照 index.html 中的默认输入Here is are two numbers 111-2222 and 444-5555,两种分隔符都被同一模式覆盖,直观体现了“字符类 = 一组字符中的任意一个”。
4.2 按非单词字符切分:/\W+/与捕获组保留分隔符
字符类最常见的工程用途是“按非单词字符切分文本”。仓库中有两处相互印证的实现:
session02 的 2-08 split 示例:
var r = /(\W+)/; var words = s.split(r); for (var i = 0; i < words.length; i++) { createP(words[i]); }Coding Challenge #38 Word Interactor:
var words = s.split(/(\W+)/); for (var i = 0; i < words.length; i++) { var span = createSpan(words[i]); span.parent(output); if (!/\W+/.test(words[i])) { span.mouseOver(highlight); } }这里有两个值得展开的细节:
\W+的语义:\W匹配任意非单词字符(空格、标点、换行等),+表示连续出现,因此整段文本会被按“空白与标点”切开,得到干净的单词序列;- 捕获组的副作用:
split中若正则包含捕获括号,JavaScript 会把分隔符本身也保留进结果数组。Word Interactor 正是利用这一点——words[i]交替出现“单词”与“分隔符”,随后用!/\W+/.test(words[i])判断当前片段是否是非单词字符,从而只给真正的单词挂上mouseOver高亮交互(点击单词会随机变色)。
4.3 用\d+过滤数字 token:字符类作为谓词
Coding Challenge #40.1 Word Counts 统计词频时,同时用到了两个字符类:
var tokens = allwords.split(/\W+/); for (var i = 0; i < tokens.length; i++) { var word = tokens[i].toLowerCase(); if (!/\d+/.test(word)) { if (counts[word] === undefined) { counts[word] = 1; } else { counts[word]++; } } }split(/\W+/):与 4.2 相同,按非单词字符切分出 token;/\d+/.test(word):用\d+判断 token 是否包含数字,从而把“2021”这类纯数字 token 从词频统计中剔除。
这种“切分用\W+、筛选用\d+”的组合,是字符类在文本处理管线(tokenize → filter)中的标准打法;对应 Processing 版本的注释 CC_040_1_wordcounts.pde 也保留了split("\\W+")的对照写法(Java 字符串中需转义为\\W)。
4.4 replace 场景:\d类与捕获组配合
session02 的 2-09 replace 示例 展示字符类如何参与替换逻辑:
var r = /(\d{3})-(\d{4})/g; var newstring = s.replace(r, replacer); function replacer(match, group1, group2) { console.log(arguments); return match; }(\d{3})-(\d{4})中,\d速写类定义了两段数字,-是字面连字符,捕获组则把两段数字分别提取为group1、group2。替换函数中arguments[0].length + arguments[1].length + arguments[2].length恰好等于整个匹配串的长度,验证了捕获组内容与完整匹配之间的关系。由此可见,字符类解决“匹配哪些字符”,捕获组解决“提取哪部分”,二者经常联用。
五、字符类与元字符、捕获组的关系
字符类并非孤立语法,它与课程系列中相邻两节紧密衔接:
- 与元字符(2.2)的关系:
\d、\w、\s这类速写类本质上就是“预定义好的字符类”;而^、-、]等在字符类内部会被重新解释(取反、区间、字面量),这正是元字符“上下文相关”的典型案例。参见 2.2 元字符。 - 与捕获组(2.4)的关系:字符类只能“选中字符”,无法“保存字符”;一旦需要在替换或后续逻辑中复用被匹配的内容,就必须用圆括号捕获组。参见 2.4 捕获组。
- 与反向引用(2.5)的关系:字符类匹配的结果无法反向引用,只有捕获组能通过
\1、\2被引用。参见 2.5 反向引用。
六、动手实验:在仓库示例中验证字符类
方式一:直接运行 session02 示例
仓库 Courses/programming_with_text/session02 下的三个示例均可直接打开运行:
2-0607_regexTestMatchExec/index.html:验证[-.]字符类同时匹配111-2222与444.5555;2-08_regexSplit/index.html:把彩虹定义文本按\W+切分成单词序列;2-09_regexReplace/index.html:观察(\d{3})-(\d{4})在 replace 回调中的匹配与分组。
这些页面通过https://cdn.jsdelivr.net/npm/p5@1.4.1/lib/p5.min.js引入 p5.js,sketch.js使用select()、createP()等 p5 DOM 方法,浏览器直接打开即可交互(输入文本 → 点击 submit → 查看输出)。
方式二:浏览器控制台快速验证
不需要任何项目代码,在开发者工具控制台即可验证字符类语义:
/[abc]/.test('xax') // true,xax 中含有 a /[^0-9]/.test('2026') // false,全是数字 '111-2222 and 444.5555'.match(/(\d{3})[-.]\d{4}/g) // ["111-2222", "444.5555"] 'a, b; c! d'.split(/\W+/) // ["a", "b", "c", "d"]方式三:把字符类搬进自己的 p5.js 草图
参照 CC_038 Word Interactor 的最小骨架,可以写出一个“点击单词变色”的交互:
function newText() { var s = textfield.value(); var words = s.split(/(\W+)/); for (var i = 0; i < words.length; i++) { var span = createSpan(words[i]); if (!/\W+/.test(words[i])) { span.mouseOver(highlight); } } } function highlight() { this.style('background-color', color(random(255), random(255), random(255))); }注意split(/(\W+)/)的捕获括号会把分隔符一并保留,这是后续用/\W+/.test()区分“单词”与“标点”的前提——如果去掉括号,数组中将只剩单词、无法保留排版用的空白与标点。
七、常见误区与调试建议
- 把
.当字面点号用:/111.2222/中的.匹配任意字符,能匹配111a2222;要匹配字面点号必须转义为\.或放入字符类[.]。课程示例用[-.]正是为了让点号恢复字面意义。 \w包含下划线:\w等价于[A-Za-z0-9_],因此\W+切分不会把下划线当作分隔符;若需要“只按空白切分”,应使用\s+而不是\W+。- 区间顺序与大小写:
[a-Z]是非法或语义混乱的区间,应写作[a-zA-Z];区间按字符编码顺序定义,[z-a]不会匹配任何内容。 - 取反类会匹配换行:
[^abc]匹配除 a、b、c 外的一切字符,包括换行;若想“排除整段字符串”,取反类并不适用,应使用负向前瞻等高级断言。 - 字符类内无须转义大部分元字符:
[.]、[*]中的点号和星号都是字面量;需要特别小心的只有\、]、-、^四个字符的位置语义。
调试时建议把正则先写成字面量/[abc]/并在控制台逐步叠加(先验证字符类,再加量词、再加捕获组),每一步都观察test()/match()的返回结果,这与课程 2.6、2.7 两节讲解的test/match/exec调试方法一脉相承(见 2.6 test 与 match、2.7 exec)。
小结
字符类用一对方括号解决了正则表达式中最基础也最常用的问题——“这个位置可以是哪些字符中的任意一个”。从本课程 2.3 的定义出发,本文结合仓库证据给出了三层实践:语法层面([...]、区间、^取反、\d/\w/\s速写类)、调用层面(test、match、split、replace中的用法)、以及项目层面(session02 正则示例、CC_038 Word Interactor、CC_040.1 Word Counts)。掌握字符类之后,建议继续阅读 2.4 捕获组 与 2.5 反向引用,把“选字符”升级为“存字符、引用字符”,从而完成文本处理工具的完整拼图。
- 教程
- 文档
- 示例工程
【免费下载链接】website-archive
Archive of the Coding Train website (first version)
相关推荐
Label Studio 安装部署指南:从零到可访问的最短路线
Label Studio 安装部署指南:从零到可访问的最短路线 Label Studio 是一款开源的多类型数据标注工具,支持文本、图像、音频、视频,标注结果以
数据标注人工智能JavaScript正则表达式中的字符类详解
JavaScript正则表达式中的字符类详解 你是否曾经在处理文本数据时遇到过这样的困扰:需要从复杂的字符串中提取特定类型的字符,比如电话号码中的数字、邮件地址
JavaScript 正则表达式中的字符类详解
JavaScript 正则表达式中的字符类详解 正则表达式是处理字符串的强大工具,而字符类 Character Classes 则是正则表达式中最基础也最常用的
文档/教程前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考