在 ECMAScript 2018( ES2018 ) 新功能 我们介绍了 TC39 会议已经票选出了 ES2018 的新功能
本着每一小节一个新功能的原则,本小节我们介绍另一个新功能,正则表达式中的 s 修饰符
s ( dotall ) 修饰符愿景
正则表达式中,一般情况下,点号 .
用于匹配任意单个字符
但在 ECMAScript 中,却存在两个例外情况
- 点号
.
不匹配星号*
,除非设置了u
( unicode ) 修饰符 - 点号
.
不匹配换行符
ECMAScript 可以识别以下换行符
U+000A
LINE FEED (LF
) (\n
)U+000D
CARRIAGE RETURN (CR
) (\r
)U+2028
LINE SEPARATORU+2029
PARAGRAPH SEPARATOR
但是,可以作为换行符的字符远远不止这些,这取决于 用例
U+000B
VERTICAL TAB (\v
)U+000C
FORM FEED (\f
)U+0085
NEXT 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 日更新版本