正则表达式:模式匹配入门 · 第 1 / 6 节

第 1 课:匹配纯文本的模式

本课目标:

  • 说出正则表达式是什么,以及它拿什么来做匹配。
  • 匹配纯字面量文本,并读懂 testmatch 的结果。
  • 区分字面量字符和特殊字符(元字符)。

先修条件:你会在控制台里调用 "text".match(...) 这样的方法 | 下一篇 02 >>

你粘贴过的模式,只是一套你没学过的字母表

你复制过“能校验邮箱”的正则,却指不出哪一段在做什么。这不是记性问题:从来没有人把这个模式赖以拼写的字母表交到你手上。正则表达式是一门微型语言,和任何语言一样,它从最乏味的情形讲起:那些只匹配自己的字符。在 \d.+? 不再像乱码之前,你需要先打好地基:模式到底在和什么做匹配,以及“特殊字符”究竟是什么意思。本课只讲这层地基,后面的一切都建在它上面。

讲解

正则表达式(regular expression,简称 regex)是一种用来在字符串里匹配字符组合的模式1。你交给引擎两样东西:一个模式和一个字符串,它告诉你模式是否出现、出现在哪里。在 JavaScript 里,模式写在两条斜杠之间,比如 /cat/,而字符串就是你拿来测试它的那段文本。

最简单的模式是字面量(literal):只匹配自己的字符。模式 /cat/ 匹配确切的序列 “cat”,无论它出现在哪里1。最后这半句比初学者预想的更重要:模式需要等于整个字符串,只要能在字符串里面被找到就算成功。

你通过方法来运行一个模式。有两个你会一直用到:test 返回 truefalse,回答“这个模式是否出现在字符串里的任何位置”;match 返回实际匹配到的文本1。正则既可以配合 RegExp 的方法(如 test)使用,也可以配合 String 的方法(如 match)使用1

不带全局标志时,match 成功后返回一个数组:索引 0 的元素是整个匹配到的文本,另外还带着 index 这样的额外属性,告诉你它在哪里被找到2。眼下,把索引 0 的元素读成“模式匹配到的那段子串”就够了。

到目前为止,每个字符都是字面量。但有些字符是特殊字符:它们是指令,不是字母。当你需要的不止是直接匹配,比如“某样东西出现一次或多次”或“任意一个数字”,就要在模式里使用特殊字符1.*+?^$[]()\ 这些字符不匹配它们自己,每一个都是一段语法。这些特殊字符叫作元字符(metacharacter),后面的每一课其实都是在一次讲清其中一小群。眼下,你只需要在脑子里记住这个划分:字母和数字是字面量,那一小撮标点符号是指令。

完整示例(跟着做)

假设你想知道一行日志是否提到了错误。打开浏览器 DevTools 控制台(或 Node REPL),试一下:

一步步看:/ERROR/ 是五个字面量字符,没有一个是特殊字符,所以引擎寻找确切的连续文本 “ERROR”,没有找到,返回 false/WARN/ 在索引 11 处被找到,所以 test 返回 truematch 交回匹配到的文本和它的位置。你没有做任何花哨的事:你搜索了字面量文本,然后读了结果。

你来试试(填空示例)

你想检查一个文件名是否包含单词 “draft”。填上缺失的那一块,让这个检查成为一次字面量搜索:

答案:空格处填字面量 draft,得到 /draft/.test(name)。d-r-a-f-t 这几个字符都是字面量,引擎搜索这段确切的连续文本,在 “report-draft-2.md” 里找到了它,返回 true。注意你从头到尾都不需要让模式等于整个文件名:字面量模式只要在字符串任何位置被找到就匹配成功。

小结 + 下节课预告

正则是拿来和字符串做匹配的模式。字面量字符匹配自己,字面量模式只要在字符串任何位置被找到就算成功,不需要等于整个字符串。test 返回布尔值;match 在索引 0 处返回匹配到的文本。还有一些字符是元字符:它们是指令,不是字母。下一课我们会见到第一族真正的元字符:字符类。它让模式里的一个位置匹配一整字符,而不是单个固定的字母,我们也会最终钉清那个 . 到底做什么。

Footnotes

  1. MDN: Regular expressions (JavaScript Guide) — https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions 2 3 4 5

  2. MDN: String.prototype.match() — https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match

练习

01

打开浏览器 DevTools 控制台(或运行 node)。定义 const s = "the quick brown fox";。先预测再运行下面每一条:/quick/.test(s)、/QUICK/.test(s) 和 s.match(/o/)。

第 1 级(热身)
完成标准 · 本地勾选
02

仍然在控制台里,运行 "a.b.c".match(/./)。你预期会匹配到字面量的点,但看看索引 0 的元素实际是什么。然后用一句话解释为什么结果是这样。

第 2 级(进阶)
完成标准 · 本地勾选

我的笔记

记下想法、痛点、没懂的地方。只写进这门课的附录,正课文件不动。