前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库JavaScript 正则 s标志dotAll与m标志区别
JavaScript数据处理

正则的 s 标志是干什么的?和 m 标志有什么区别?

s 标志(dotAll)让 . 也能匹配换行符,默认情况下 . 遇到换行就停。m 标志(multiline)不管点号,它改变的是 ^ 和 $,让它们匹配每一行的开头和结尾,而不只是整个字符串的首尾。名字里带 multiline 的 m 并不能让点号跨行,这是最常见的误解。

前端进阶之旅 · 一题精讲更新于 2026.09.29
JavaScript#数据处理
先看核心答案读代码示例
理解线索

一个管字符,一个管位置

  1. s(dotAll)点号的匹配范围扩大到换行符,包括 \n 和 \r
  2. m(multiline)^ 和 $ 除了匹配整个字符串的首尾,还匹配每一行的首尾
  3. 组合使用两者互不干扰,需要跨行内容又要按行定位时一起开

m 模式下的 ^ 和 $ 匹配的是位置,不会吃掉换行符。所以用 /^.*$/gm 逐行匹配时,每一行的结果里都不带 \n。

核心回答

先记住这个答案

默认情况下,正则里的 . 能匹配几乎所有字符,唯独不匹配换行符,所以 /a.b/ 匹配不了 'a\nb'。s 标志(dotAll)就是把换行符也纳入点号的范围,/a.b/s 就能匹配了。m 标志(multiline)解决的是另一件事:默认 ^ 只匹配整个字符串的开头,$ 只匹配结尾,开了 m 之后,它们还会匹配每一行的开头和结尾。一个管点号能不能跨行,一个管锚点按不按行,两者互相独立,可以一起用。

  • s 管点号:让 . 能匹配换行
  • m 管锚点:让 ^ 和 $ 按行匹配
  • 两个标志互相独立,可以一起用
  • 不开 s 时用 [\s\S] 匹配任意字符

先看两个标志各自改变了什么

同一段含换行的文本,分别用四个正则去测。

分别验证点号和锚点JavaScript
const text = 'a\nb'

console.log(/^a.b$/.test(text)) // 点号不匹配换行
console.log(/^a.b$/s.test(text)) // 开 s,点号吃掉了换行
console.log(/^b$/.test(text)) // ^ 只认整个字符串的开头
console.log(/^b$/m.test(text)) // 开 m,第二行的开头也算
查看输出与解释
false
true
false
true

第二行只有开了 s,点号才能跨过 \n。第四行只有开了 m,正则 ^b$ 才能把第二行当成独立的一行。反过来试也一样:/^a.b$/m 还是 false,因为 m 不管点号;/^b$/s 也还是 false,因为 s 不管锚点。 点号默认排除的不只是 \n,还有 \r 以及 Unicode 的行分隔符 \u2028 和段分隔符 \u2029。Windows 的换行是 \r\n,不开 s 时 . 两个都匹配不了。

实际用法:处理多行日志

处理日志、Markdown、配置文件时,这两个标志最常用。比如从日志里提取一整条错误,错误信息后面跟着多行调用栈。

用 s 跨行提取,用 m 按行定位JavaScript
const log = '[ERROR] 请求失败\n  at fetchUser\n  at main\n[INFO] 重试成功'

console.log(log.match(/\[ERROR\].*/)[0]) // 不开 s,遇到换行就停

// 开 s,懒惰匹配一直吃到下一条日志之前
const block = log.match(/\[ERROR\].*?(?=\n\[)/s)[0]
console.log(block.split('\n').length) // 错误信息加两行调用栈

console.log(log.match(/^\[\w+\]/gm).join(' ')) // 开 m,每行行首都能匹配
查看输出与解释
[ERROR] 请求失败
3
[ERROR] [INFO]

第一个不开 s,只拿到了第一行,调用栈全丢了。第二个开了 s,于是 .*? 可以跨行,配合前瞻 (?=\n\[) 在下一条日志开头之前停下,拿到了完整的三行。第三个用 m 让 ^ 匹配每一行的开头,把每条日志的级别都找出来了。

没有 s 的年代怎么写
s 标志是 ES2018 才加的。以前要匹配包括换行在内的任意字符,常见写法是 [\s\S],意思是「空白或非空白」,合起来就是所有字符,也有人写 [^]。老代码里看到这两种写法,意思和开了 s 的点号一样。现在直接用 s 更好读。
回答前,多想一步

容易答错的地方

以为 m 能让点号跨多行
multiline 这个名字很容易让人以为它和「多行匹配」有关,但它只改变 ^ 和 $ 的含义。点号能不能匹配换行,只由 s 决定。想跨行匹配内容却只开了 m,结果不会有任何变化。
开了 s 就用贪婪匹配吞整段
/<div>.*<\/div>/s 会从第一个 <div> 一直匹配到最后一个 </div>,中间所有内容都被吞进去。跨行匹配时通常要用懒惰量词 .*?,或者用前瞻限定结束位置。解析 HTML 这类嵌套结构,正则本来就不合适,应该用 DOMParser。
试着用自己的话回答

面试官还会怎么问?

s 和 m 可以同时用吗?

可以,写成 /^BEGIN.*?END$/sm。s 让中间的 .*? 能跨行,m 让 ^ 和 $ 匹配 BEGIN 所在行的开头和 END 所在行的结尾。适合从大段文本里提取「某行开始、某行结束」的块,比如提取 PEM 证书内容。

怎么判断一个正则开了哪些标志?

读它的属性。re.dotAll 对应 s,而 re.multiline 对应 m,还有 re.global 对应 g。re.flags 会返回所有标志组成的字符串,比如 'gms'。

m 模式下 $ 匹配在换行符前面还是后面?

前面。$ 匹配的是换行符之前的那个位置,^ 匹配的是换行符之后的那个位置,它们都是零宽的,不会吃掉换行符本身。所以 /^.*$/gm 拿到的每一行都不带 \n。

从一道题,走向一组知识

把知识连起来

数据处理

带 g 的正则连续调用 test,为什么结果一会儿 true 一会儿 false?

s 和 m 改变匹配规则,g 和 y 改变匹配从哪里开始,后者还会让 lastIndex 留下状态。

数据处理

有了 matchAll,为什么不再推荐用 while 循环调 exec?

逐行提取多段内容时,m 标志常和 matchAll 一起用,那题讲怎么拿到每一次匹配的分组。

参考资料

  • JavaScript:数据处理参考资料

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 先看两个标志各自改变了什么
  3. 实际用法:处理多行日志
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑