在 ECMAScript 2018( ES2018 ) 新功能 我们介绍了 TC39 会议已经票选出了 ES2018 的新功能
本着每一小节一个新功能的原则,本小节我们介绍另一个新功能,正则表达式中的 s 修饰符
s ( dotall ) 修饰符愿景
正则表达式中,一般情况下,点号 . 用于匹配任意单个字符
但在 ECMAScript 中,却存在两个例外情况
- 点号
.不匹配星号*,除非设置了u( unicode ) 修饰符 - 点号
.不匹配换行符
ECMAScript 可以识别以下换行符
U+000ALINE FEED (LF) (\n)U+000DCARRIAGE RETURN (CR) (\r)U+2028LINE SEPARATORU+2029PARAGRAPH SEPARATOR
但是,可以作为换行符的字符远远不止这些,这取决于 用例
U+000BVERTICAL TAB (\v)U+000CFORM FEED (\f)U+0085NEXT LINE
这会导致正则表达式中的点号的 . 行为出现问题
- 根据语法规则,它排除了一些换行符,但又不是全部,这通常与开发人员的用例不匹配
- 一般情况下,它通常可以匹配任意单个字符,但其实又没有
而这份提案,用于修正后一个问题,就是让 . 实际上可以匹配任意字符
之前,开发者如果希望 . 可以匹配任意单个字符,包括这些行终止符,仅仅使用一个点号是不可能实现的
/foo.bar/.test('foo\nbar'); // → false
为了能够匹配任意字符,开发者不得不采用 [\s\S] 或 [^] 这种神秘的解决办法
/foo[^]bar/.test('foo\nbar');
// → true
由于需要匹配任何字符是很常见的,其它语言的正则表达式引擎则提供了一种模式可以 匹配任何字符,包括行终止符
-
提供了
DOTALL或SINGLELINE常量或/s修饰符让正则表达式引擎开启匹配换行支持- Java 提供了
Pattern.DOTALL常量 - C# 和 VB.NET 提供了
RegexOptions.Singleline常量 - Python 则同时提供了
e.DOTALL和re.S常量
- Java 提供了
-
某些语言的正则表达式引擎则支持嵌入式标志
(?s) -
某些语言的正则表达式引擎则提供了
s修饰符
注意,将修饰符命名为 s ( singleline 的缩写 ) 和 dotAll 是业内通用的传统
有一个例外就是 Ruby,它的 m 修饰符 ( Regexp::MULTILINE ) 同样能够开启 dotAll 模式
然而,不幸的是,JavaScript 不可能再使用 m 修饰符,因为它已经存在了,否额会破坏兼容性
提出的解决方案
我们建议为 ECMAScript 正则表达式添加一个新的 s 修饰符,用于匹配任何字符,包括行终止符
/foo.bar/s.test('foo\nbar'); // → true
高阶 API
const re = /foo.bar/s; // Or, `const re = new RegExp('foo.bar', 's');`. re.test('foo\nbar'); // → true re.dotAll // → true re.flags // → 's'
FAQ
向前兼容性怎么样 ?
有正则表达式模式的含义不受此提议的影响,因为新 s 修饰符的行为是新添加
dotall 模式会对 multiline 模式产生什么影响
如果 s 和 m 同时存在,dotall 模式可能会对 multiline 模式产生一些影响,因为 s 修饰符代表单行,而与 m/multiline 相矛盾
这有点不幸,因为本提案只是遵循其他正则表达式引擎中已建立的命名传统,如果选择任何其他标志名称只会引起更多混淆
某些方面说,修饰符 s 的名称 dotAll 则很明确的描述了该修饰符的效果,因此,我们建议将此模式称为dotAll 模式而不是 单行模式
两个模式是相互独立的,又可以组合在一起使用,multiline 模式只会影响锚点,而 dotall 模式只会影响点号 .
当同时设置了 s ( dotAll ) 和 m ( multiline ) 修饰符,. 可以匹配任何字符,同时仍允许 ^ 和 $ 分别匹配字符串中的行终止符之后和之前
语法规范
实现
该提案已经得到众多浏览来的支持,包括
- V8,Chrome 62+
- JavaScriptCore,Safari 技术预览版 39a
- XS,2018 年 1 月 17 日更新版本