☰
Modern JavaScript Tutorial 正则表达式系列:锚点 `^` `$` 的多行模式与 `m` 标志详解
2026/10/7 2:37:39 网站建设 项目流程
  • 文档/教程
  • 前端

【免费下载链接】en.javascript.info

Modern JavaScript Tutorial

项目地址:https://gitcode.com/gh_mirrors/en/en.javascript.info
点击查看免费下载

导读

在处理多行文本(如日志、配置文件、Markdown 正文)时,正则表达式的行首、行尾匹配是最常见也最容易出错的需求。本篇文章聚焦 Modern JavaScript Tutorial 中「正则表达式多行模式(Multiline mode)」这一章节,系统讲解m标志如何改变锚点^与$的匹配行为:默认情况下它们只匹配整个字符串的开头与结尾,而开启多行模式后则会匹配每一行的开头与结尾。读完本文,你将彻底理解^、$与换行符\n的本质区别,并能用它们准确提取多行文本中每行的关键内容。

一、什么是多行模式:标志m

JavaScript 的正则表达式支持 6 个标志(flags),分别是i(忽略大小写)、g(全局匹配)、m(多行模式)、s(dotall,让.匹配换行符)、u(完整 Unicode 支持)、y(sticky 粘性匹配),详见 正则表达式入门章节。

其中,标志m(multiline)的职责非常单一:

多行模式只影响锚点^与$的行为。

在默认(非多行)模式下,^只在整个字符串的开头匹配,$只在整个字符串的结尾匹配;而在多行模式下,它们不仅匹配文本整体首尾,还会在每一行的开头 / 结尾处匹配。

关于^与$在默认模式下的基础行为,可以回看本系列前一篇 锚点:字符串开头 ^ 与结尾 $,其中强调了一个关键性质:锚点不是字符,而是"零宽度"(zero width)的测试——它们不消费任何字符,只是让正则引擎在当前位置检查"是否处于文本开头/结尾"这一条件。理解这一点,对理解多行模式至关重要。

二、行首匹配:^在多行模式下

2.1 开启m后,每行开头都能命中

假设我们有一段三行文本,记录了三名选手的名次:

let str = `1st place: Winnie 2nd place: Piglet 3rd place: Eeyore`; console.log( str.match(/^\d/gm) ); // 1, 2, 3

模式pattern:/^\d/gm由三部分组成:^要求当前位置是"行首",\d要求紧接着是一个数字,g表示查找全部匹配,m开启多行模式。最终结果得到1, 2, 3——三行的第一个数字都被捕获了。

2.2 关闭m后,只有整个文本开头的数字能命中

同样的文本、同样的^与\d,只是去掉m标志:

let str = `1st place: Winnie 2nd place: Piglet 3rd place: Eeyore`; console.log( str.match(/^\d/g) ); // 1

结果只剩一个1。原因正如文档所强调的:默认情况下^只在文本开头匹配,而文本开头只有一个,所以只取到第一个数字。

2.3 "行首"的精确定义

这里有一个容易忽略的细节,文档用专门的提示框给出正式定义:

"行首"(start of a line)正式含义是"紧跟换行符之后":多行模式下,^测试会在所有前面紧邻换行符\n的位置匹配,当然也包括文本的最开头。

换句话说,^在m模式下匹配的位置集合是:{文本开头} ∪ {每个 \n 之后的紧邻位置}。这个定义决定了多行模式下"行"的边界就是\n。

三、行尾匹配:$在多行模式下

$的行为与^完全对称。

3.1 开启m后,每行结尾的数字都能命中

把上一节的例子改造成"查找每一行最后一个数字":

let str = `Winnie: 1 Piglet: 2 Eeyore: 3`; console.log( str.match(/\d$/gm) ); // 1,2,3

模式pattern:\d$要求"一个数字紧邻行尾",配合g与m,得到三行各自的末尾数字1, 2, 3。

3.2 关闭m后,只有整个文本的最后一个数字命中

如果去掉m:

let str = `Winnie: 1 Piglet: 2 Eeyore: 3`; console.log( str.match(/\d$/g) ); // 3

由于$默认只匹配整个文本的结尾,而整个文本以3收尾,所以只找到最后一个数字。

3.3 "行尾"的精确定义

与"行首"对应,文档同样给出正式定义:

"行尾"(end of a line)正式含义是"紧邻换行符之前":多行模式下,$测试会在所有后面紧邻换行符\n的位置匹配,当然也包括文本的最末尾。

也就是说,$在m模式下匹配的位置集合是:{文本末尾} ∪ {每个 \n 之前的紧邻位置}。注意3之后没有换行符,但它处于文本末尾,因此依然满足$的匹配条件。

四、用\n代替^ $行吗?区别在哪里

既然多行模式让^、$可以定位行首行尾,那为什么不直接匹配换行符\n呢?文档专门用一个小节回答了这个问题。

4.1 用\n匹配的后果

把上一节的pattern:\d$改成pattern:\d\n:

let str = `Winnie: 1 Piglet: 2 Eeyore: 3`; console.log( str.match(/\d\n/g) ); // 1\n,2\n

结果从 3 个匹配变成了 2 个。原因有两点:

  1. 最后一行没有换行符:Eeyore: 3之后是文本末尾而不是\n,所以3\n无法匹配。而$锚点可以匹配文本末尾,因此3在\d$(带m)中能命中。
  2. \n是字符,会进入匹配结果:\n是实实在在的字符,因此每次匹配结果中都包含换行符本身(输出为1\n,2\n)。而^、$是零宽度的测试,它们只检查位置条件,不会把任何字符带入匹配结果。

4.2 选择依据

文档给出了非常清晰的取舍结论,可以直接当作决策准则:

  • 当你需要把换行符本身作为结果的一部分(例如按行切分后要保留行结束符)时,用\n;
  • 当你只是需要找到位于某行开头或结尾的内容(换行符不应该出现在匹配结果里)时,用带m标志的锚点^/$。

用一句话概括:锚点管"位置",\n管"字符"。锚点只做条件测试、零宽度、不消费字符;而\n是一个真实的字符,参与匹配并出现在结果中。这与前一篇 锚点章节 强调的"锚点零宽度"特性一脉相承。

五、实战延伸:多行模式与锚点的典型配合

在 Modern JavaScript Tutorial 的正则表达式系列中,多行模式常与其他锚点类特性配合使用,这里给出几个基于仓库既有内容的实战视角。

5.1 多行模式 + 全字符串校验的边界

在 锚点章节的练习题 中,^...$组合被用来校验整个字符串是否完全符合某种格式(例如时间12:34)。练习的解答特意强调:^与$是测试而非字符,即使对空字符串"",^与$也能同时命中。这与多行模式直接相关:一旦加上m,^...$就退化为"逐行校验",此时每一行都会被独立要求满足完整格式——这是实现"逐行格式校验"的高效手段。

5.2 多行模式 + 单词边界\b

另一类与行首行尾高度相关的锚点是单词边界\b(详见 单词边界章节)。\b同样是零宽度测试,它检查位置两侧是否一边是单词字符\w、一边不是。实际处理多行文本时,常把^、$与\b组合:^\b\d+\b$(带m)可以精确匹配"整行恰好是一个独立的数字"。这类模式在日志解析、配置文件校验、命令行输出处理中非常实用。

5.3 提取结果的注意事项:match与g标志

本文所有示例都依赖str.match(regexp)配合g标志返回全部匹配数组;若没有g,match只返回第一个匹配;若没有任何匹配,match返回null而非空数组。完整的match/matchAll/replace/exec行为可查阅本系列 正则方法与字符串方法,那里还覆盖了lastIndex与全局正则复用的陷阱——这些细节在真实项目中排查"为什么只匹配到第一行"时尤为重要。

六、小结

场景模式匹配结果
每行开头的数字/^\d/gm每行第一个数字(如1, 2, 3)
每行结尾的数字/\d$/gm每行最后一个数字(如1,2,3)
数字 + 换行符本身/\d\n/g仅非末行命中,且结果含\n
整个文本开头的数字/^\d/g仅第一个数字
整个文本结尾的数字/\d$/g仅最后一个数字

核心要点回顾:

  1. 标志m只改变^与$,对.、\d、\b等其他语法没有影响;
  2. 多行模式下:^匹配"文本开头 + 每个\n之后",$匹配"文本末尾 + 每个\n之前";
  3. 锚点是零宽度测试:不消费字符、不进入匹配结果,只检查位置条件;
  4. \n是真实字符:需要换行符进入结果时用它,需要定位行首行尾时用锚点。

以上内容整理自 9-regular-expressions/05-regexp-multiline-mode/article.md,并结合同系列 锚点章节、正则表达式入门章节 与 正则方法章节 进行了扩展讲解。建议在阅读本系列时按"入门 → 锚点 → 多行模式 → 单词边界 → 正则方法"的顺序循序渐进,掌握正则表达式的完整能力。

  • 文档/教程
  • 前端

【免费下载链接】en.javascript.info

Modern JavaScript Tutorial

项目地址:https://gitcode.com/gh_mirrors/en/en.javascript.info
点击查看免费下载
上一篇:Quagga 路由协议栈快速上手:从零搭建 BGP 与 OSPF 实验环境
下一篇:fanbox-dl:一条命令批量备份 FANBOX 创作者内容的完整指南

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

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

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

立即咨询