我经常忘记正则表达式修饰符m
及其s
差异。有什么好的方法来记住它们?
据我了解,它们是:
'm' 用于多行,因此 将多次匹配字符串的开头和字符串的结尾
^
。$
(除以\n
)'s' 使得点将匹配换行符
通常,我只是使用
/some_pattern/ism
但相应地使用它们可能会更好(在我的情况下通常是“s”)。
你认为什么是记住它们的好方法,而不是每次都忘记哪个是哪个?
多年来一直使用正则表达式但仍然不了解这两个修饰符如何工作的人并不罕见。正如您所观察到的,名称“多行”和“单行”并不是很有帮助。它们听起来一定是相互排斥的,但它们是完全独立的。我建议您忽略名称并专注于它们的作用:m
更改锚点的行为(^
和$
),并s
更改点的行为(.
)。
混合模式的一位杰出人物是 Ruby 的作者。他在 Perl 的基础上创建了自己的正则表达式实现,但他决定拥有^
并$
始终作为行锚——也就是说,多行模式始终处于打开状态。不幸的是,他还错误地将 dot-matches-everything 模式命名为multiline。所以 Ruby 没有s
修饰符,但它的m
修饰符可以s
做其他风格的事情。
至于总是使用/ism
,我建议不要。正如您所发现的,它基本上是无害的,但它会向任何试图弄清楚正则表达式应该做什么的人(或者甚至是未来的你自己)发送一个令人困惑的信息。
我喜欢“man perlre”中的解释:
m 将字符串视为多行。
s 将字符串视为单行。
对于多行,^ 和 $ 适用于单独的行(即在换行符之前和之后)。
使用单行,^ 和 $ 适用于整体,而 \n 只是成为您可以匹配的另一个字符。
[错误]通过使用您所描述的 m 和 s,我希望第二个优先,因此您将始终使用 /ism 处于多行模式。[/错误的]
我读得不够远:
“/s”和“/m”修饰符都覆盖了 $* 设置。也就是说,无论 $* 包含什么,没有 "/m" 的 "/s" 将强制 "^" 仅匹配字符串的开头,而 "$" 仅匹配末尾(或仅在换行符之前字符串的结尾)。一起,作为 /ms,他们让“。” 匹配任何字符,同时仍然允许 "^" 和 "$" 分别匹配字符串中的换行符之后和之前。
我可以更清楚地写出它们是什么,以及一种记住它们的方法,并且我将其写成与 JavaScript 相关:
s
标志。它只有m
国旗。截至 2020 年 1 月,Firefox 仍然没有它,而 Chrome 有它。NodeJS 拥有它。它在 ES2018 规范中。 s
也称为dotall
or 。singleline
它实际上只是为了.
匹配任何 (ASCII) 字符,包括\n
, \r
, \u2028
(换行符), \u2029
(段符)。当人们问你,什么是.
匹配的?如果你回答“任何字符”,那么它并不完全正确。它是除换行符\r
和 unicode 换行符和分段符之外的所有 (ASCII) 字符。为了让它真正匹配所有 ASCII 字符,它需要打开s
标志。 s
标志,它可以是[^]
, [\s\S]
, [\d\D]
, etc, 或(.|\s)
.s
传统 JavaScript 中缺少的标志。m
国旗。它代表多行。它真的很简单:没有m
标志,^
and$
将只匹配整个字符串的开头和结尾。所以"John Doe\nMary Lee".match(/^John Doe$/)
不会匹配,"John Doe\nMary Lee".match(/^John Doe$/m)
会匹配。就这样。不要以太复杂的方式考虑它。它只是改变了匹配方式^
和$
匹配方式。a
任何字符,包括换行符和f
, 但a
必须在行首并且f
必须在行尾,即使在 2000 行文本中,那么"a b c \n d e f\nha".match(/^a.*f$/ms)
需要用过的。匹配,和.
匹配行首和行尾。\n
^
$
就是这样。以上是在已经支持该s
标志的 NodeJS 和 Chrome 上测试的。(并且该m
标志长期以来一直受到支持)。请记住,您始终可以s
使用以下方法修复标志丢失问题[^]
现在,为什么过去被ms
或被ism
大量使用?因为很多时候,当我们有一个非常长的字符串(例如 2000 行 HTML)时,例如我们返回的一些网页内容,我们很少希望匹配^
整个字符串的开头和$
结尾的整个字符串。所以这就是我们使用m
标志的原因。现在,我们可能想要跨行匹配,因为(尽管不推荐使用正则表达式来匹配 HTML),例如,我们可能会使用/<h1>.*?</h1>/
一个非贪婪的标题匹配。我们不介意\n
内容中的 ,因为 HTML 的作者很可能有一个\n
(或没有)。这就是我们使用“dotall”标志的原因s
。
但是,如果您尝试从网页中提取一些信息,您可能不会关心某些内容是在行首还是行尾(因为 HTML 文件中可以有空格(或作为缩进),而且它不会' 不影响页面内容(通常,除非有<pre>
等),所以你不需要使用^
or $
,因此你可以忘记m
标志。如果你不介意使用[^]*?
代替.*?
,那么你也可以忘记s
标志——故事结束。
Perl Cookbook 用两句话说:
/m
和之间的区别/s
很重要:/m
在换行符旁边生成^
和$
匹配,而在换行符旁边生成/s
匹配.
。您甚至可以一起使用它们——它们不是相互排斥的选项。
也许这样,我永远不会忘记:
当我想跨行匹配时(通常使用 .*? 来匹配跨多行无关紧要的东西),我自然会想到多行,因此,'m'。好吧,“m”实际上不是那个,所以它是“s”。
(因为我已经很好地记住了'ism'......所以我总是能记住它不是'm',那么它一定是's')。
其他蹩脚的尝试包括:
s
用于 DOTALL,用于 DOT 匹配 ALL。
m
是多行的——它用于^
和$
匹配很多次。