【发布时间】:2010-10-29 11:05:18
【问题描述】:
我经常忘记正则表达式修饰符m 和s 及其区别。有什么好的方法来记住它们?
据我了解,它们是:
'm' 用于多行,因此
^和$将匹配字符串的开头和结尾 字符串多次。 (划分为\n)'s' 使得点将匹配甚至 换行符
通常,我只是使用
/some_pattern/ism
但是相应地使用它们可能会更好(在我的情况下通常是“s”)。
你认为什么是记住它们的好方法,而不是每次都忘记哪个是哪个?
【问题讨论】:
我经常忘记正则表达式修饰符m 和s 及其区别。有什么好的方法来记住它们?
据我了解,它们是:
'm' 用于多行,因此
^和$将匹配字符串的开头和结尾 字符串多次。 (划分为\n)'s' 使得点将匹配甚至 换行符
通常,我只是使用
/some_pattern/ism
但是相应地使用它们可能会更好(在我的情况下通常是“s”)。
你认为什么是记住它们的好方法,而不是每次都忘记哪个是哪个?
【问题讨论】:
多年来一直使用正则表达式但仍然不了解这两个修饰符如何工作的人并不罕见。正如您所观察到的,名称“多行”和“单行”并不是很有帮助。它们听起来一定是相互排斥的,但它们是完全独立的。我建议您忽略名称并专注于它们的作用:m 更改锚点的行为(^ 和 $),s 更改点的行为(.)。
混合模式的一位杰出人物是 Ruby 的作者。他基于 Perl 创建了自己的正则表达式实现,但他决定让 ^ 和 $ 始终作为行锚——也就是说,多行模式始终处于打开状态。不幸的是,他还错误地将点匹配模式命名为 multiline。所以 Ruby 没有 s 修饰符,但它的 m 修饰符与 s 在其他风格中所做的一样。
至于总是使用/ism,我建议不要这样做。正如您所发现的,它基本上是无害的,但它会向任何试图弄清楚正则表达式应该做什么的人(或者甚至是你自己,将来)发送一个令人困惑的信息。
【讨论】:
我喜欢“man perlre”中的解释:
m 将字符串视为 m 多行。
s 将字符串视为 s 单行。
对于多行,^ 和 $ 适用于单独的行(即,就在换行符之前和之后)。
单行,^ 和 $ 适用于整个,而 \n 只是成为您可以匹配的另一个字符。
[错误]按照您的描述同时使用 m 和 s,我希望第二个优先,因此您将始终处于使用 /ism 的多行模式。[/错]
我读得不够远:
"/s" 和 "/m" 修饰符都覆盖 $* 设置。也就是说,无论 $* 包含什么,没有 "/m" 的 "/s" 将强制 "^" 仅匹配字符串的开头,而 "$" 仅匹配末尾(或仅在换行符之前字符串的结尾)。一起,作为 /ms,他们让“。”匹配任何字符,同时仍然允许 "^" 和 "$" 分别匹配字符串中的换行符之后和之前。
【讨论】:
我可以更清楚地写出它们是什么,以及一种记住它们的方法,并且我将其写成与 JavaScript 相关:
s 标志。它只有m 标志。截至 2020 年 1 月,Firefox 仍然没有它,而 Chrome 有它。 NodeJS 拥有它。它在 ES2018 规范中。 s 也称为dotall 或singleline。而且它真的只是让. 匹配任何(ASCII)字符,包括\n、\r、\u2028(换行)、\u2029(换行)。当人们问你,. 匹配什么?如果你回答“任何字符”,那么它并不完全正确。它是除换行符、\r 和 unicode 换行符和分段符之外的所有 (ASCII) 字符。要让它真正匹配所有 ASCII 字符,它需要打开 s 标志。 s标志,它可以是[^]、[\s\S]、[\d\D]等,或(.|\s)。s 标志。m 标志。它代表多行。它真的很简单:没有m 标志,^ 和$ 将只匹配整个字符串的开头和结尾。所以"John Doe\nMary Lee".match(/^John Doe$/) 不会匹配,"John Doe\nMary Lee".match(/^John Doe$/m) 会匹配。就这样。不要以太复杂的方式考虑它。它只是改变了^ 和$ 的匹配方式。a,然后匹配任何字符,包括换行符和f,但a 必须在行首,f 必须在行尾,即使 out 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> 等),因此您不需要使用^ 或$,因此您可以忘记m 标志.如果您不介意使用[^]*? 而不是.*?,那么您也可以忘记s 标志——故事结束。
Perl Cookbook 用两句话说:
/m和/s之间的区别很重要:/m使^和$匹配换行符旁边,而/s使.匹配换行符。您甚至可以一起使用它们 - 它们不是相互排斥的选项。
也许这样,我永远不会忘记:
当我想跨行匹配时(通常使用 .*? 来匹配跨多行无关紧要的东西),我自然会想到多行,因此,'m'。嗯,'m'实际上不是那个,所以它是's'。
(因为我已经很好地记住了'ism'......所以我总是记得它不是'm',那么它一定是's')。
其他蹩脚的尝试包括:
s 用于 DOTALL,用于 DOT 匹配 ALL。m 是多行 -- 它用于 ^ 和 $ 匹配很多次。
【讨论】: