ECMAScript特性:正则表达式模式修饰符

本文为翻译
本文译者为 360 奇舞团前端开发工程师
原文标题:ECMAScript feature: regular expression pattern modifiers
原文作者:Dr. Axel Rauschmayer
原文地址:https://2ality.com/2025/01/regexp-modifiers.html

传统上,我们只能将诸如 i(用于忽略大小写)之类的正则表达式标志应用于整个正则表达式。ECMAScript特性“正则表达式模式修饰符”(由 Ron Buckton 提出)使我们能够仅将这些标志应用于正则表达式的部分内容。在这篇文章中,我们将探讨它们的工作原理以及使用场景。

正则表达式模式修饰符属性在2024年10月进入第4阶段,很可能会成为ECMAScript 2025的一部分。

什么是模式修饰符?

正则表达式的工作方式受所谓的标志影响,例如,标志 i 在匹配时忽略大小写:

> /yes/i.test('yes')
true
> /yes/i.test('YES')
true

模式修饰符使我们能够将标志应用于正则表达式的部分内容(而非整个正则表达式)。例如,在以下正则表达式中,标志 i 仅应用于“HELLO”:

> /^x(?i:HELLO)x$/.test('xHELLOx')
true
> /^x(?i:HELLO)x$/.test('xhellox')
true
> /^x(?i:HELLO)x$/.test('XhelloX')
false

从某种程度上说,模式修饰符就是内联标志。

语法

语法形式如下:

(?ims-ims:pattern)
(?ims:pattern)
(?-ims:pattern)

注意事项

  • 问号(?)后面的标志为启用状态。

  • 连字符(-)后面的标志为禁用状态。

  • 一个标志不能同时出现在“启用部分”和“禁用部分”。

  • 不带任何标志时,此语法只是一个非捕获组:(?:pattern)

让我们修改前面的示例:现在除了“HELLO”之外,整个正则表达式都不区分大小写:

> /^x(?-i:HELLO)x$/i.test('xHELLOx')
true
> /^x(?-i:HELLO)x$/i.test('XHELLOX')
true
> /^x(?-i:HELLO)x$/i.test('XhelloX')
false

支持哪些标志?

模式修饰符中可使用以下标志:

字面标志属性名ES版本描述
iignoreCaseES3执行不区分大小写的匹配
mmultilineES3^ 和 $ 匹配每行的开头和结尾
sdotAllES2018点号(.)匹配行终止符

欲了解更多信息,请参阅《探索JavaScript》中关于标志的部分。

其余标志不被支持,原因要么是它们会使正则表达式语义过于复杂(例如标志 v),要么是它们只有应用于整个正则表达式才有意义(例如标志 g)。

模式修饰符的使用场景有哪些?

使用场景:更改正则表达式部分内容的标志

有时,能够更改正则表达式部分内容的标志是很有用的。例如,Ron Buckton 解释说,更改标志 m 有助于匹配文件开头的Markdown前置元数据块(我对他的版本稍作修改):

const re = /(?-m:^)---\r?\n((?:^(?!---$).*\r?\n)*)^---$/m;
assert.equal(re.test('---a'), false);
assert.equal(re.test('---\n---'), true);
assert.equal(
  re.exec('---\n---')[1],
  ''
);
assert.equal(
  re.exec('---\na: b\n---')[1],
  'a: b\n'
);

这个正则表达式是如何工作的呢?

  • 默认情况下,标志 m 处于启用状态,锚点 ^ 匹配行首,锚点 $ 匹配行尾。

  • 第一个 ^ 有所不同:它必须匹配字符串的开头。这就是为什么我们在那里使用模式修饰符并关闭标志 m

下面是添加了无关空白和解释性注释的正则表达式:

(?-m:^)---\r?\n  # 字符串的第一行
(  # 用于前置元数据的捕获组
  (?:  # 一行的模式(非捕获组)
    ^(?!---$)  # 行不能以 "---" + 行结束符开头(正向先行断言)
.*\r?\n
  )*
)
^---$  # 前置元数据的结束分隔符
使用场景:内联标志

在某些情况下,标志位于实际正则表达式之外会带来不便。这时模式修饰符就派上用场了。例如:

  • 将正则表达式存储在配置文件中,例如以JSON格式存储。

  • Regex+库提供了一种模板字面量,使创建正则表达式更加方便。指定标志的语法会增加一些杂乱度,通过模式修饰符(如果它们支持所需的标志)可以避免这种情况:

regex('i')`world`
regex`(?i:world)`
使用场景:正则表达式片段可以更改标志

在复杂应用中,如果能够由较小的正则表达式组合成大型正则表达式会很有帮助。前面提到的Regex+库支持这种做法。如果一个较小的正则表达式需要不同的标志(例如因为它想要忽略大小写),那么借助模式修饰符就可以实现。

进一步阅读

  • 本文来源:ECMAScript提案“正则表达式模式修饰符”(由Ron Buckton提出)

  • 《探索JavaScript》中“正则表达式(RegExp)”章节

- END -

如果您关注前端+AI 相关领域可以扫码进群交流

 202079a90075db9b9be12e21e321f6a9.jpeg

添加小编微信进群😊

关于奇舞团

奇舞团是 360 集团最大的大前端团队,非常重视人才培养,有工程师、讲师、翻译官、业务接口人、团队 Leader 等多种发展方向供员工选择,并辅以提供相应的技术力、专业力、通用力、领导力等培训课程。奇舞团以开放和求贤的心态欢迎各种优秀人才关注和加入奇舞团。

dd8bb3664c05d3d4fb2221f4c8e8d881.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值