【问题标题】:What is a "string-ending newline" in relation to the $ metacharacter?什么是与 $ 元字符相关的“字符串结尾换行符”?
【发布时间】:2020-03-07 15:12:23
【问题描述】:

我正在研究 Mastering Regular Expressions, 3rd Edition 的正则表达式,我发现 $^ 复杂一点,这让我感到惊讶,因为我认为他们是“对称的”,除非它们被转义为它们的字面对应物。

事实上,在第129页,他们的描述略有不同,更多的词是支持$;但是我仍然对此感到困惑。

  • 关于^,只描述了两个明确的替代方案:

Caret ^ 匹配正在搜索的文本的开头,如果处于增强的行锚模式,则匹配任何换行符之后。 [...] $ [...] 匹配

  • 关于$,我的描述比较模糊:

$ [...] 匹配目标字符串的末尾以及 string-ending 换行符之前。后者很常见,允许像s$ 这样的表达式(表面上,匹配“以s 结尾的行”)来匹配…s<NL>,以s 结尾的行以换行符结尾。

$ 的另外两个常见含义是仅匹配目标文本的末尾,以及匹配任何换行符之前。

后两个含义似乎与^ 中描述的含义相当对称,但是字符串结尾的换行符 的含义呢?

目前搜索[regex] "string-ending newline"只给出onetwothree的结果,而且都是参考

$ 匹配字符串的结束位置或字符串结束换行符之前的位置。在基于行的工具中,它匹配任何行的结束位置。

【问题讨论】:

  • 这本书一般是关于正则表达式的,但它主要关注 Perl,因此我的问题中的标签。鉴于下一页上的表格,我认为该文本适用于 Perl(以及其他语言,但不适用于 awk)。
  • 好的,如果你使用 perl,你可以使用 \z 来匹配字符串的结尾,\Z 来匹配结尾或者结尾处的换行符之前。 perl 中的$m//qr//m 标志的约束。

标签: regex perl newline eol dollar-sign


【解决方案1】:

零宽度断言$ 在字符串末尾断言位置,或在字符串末尾的行终止符之前(如果有)。

使用perl中的这些代码sn-ps会更清楚:

$str = 'abc
foo';
$str =~ s/\w+$/#/;
print "1. <" . $str . ">\n\n";

$str = 'abc
foo
';
$str =~ s/\w+$/#/;
print "2. <" . $str . ">\n\n";

$str = 'abc
foo

';
$str =~ s/\w+$/#/;
print "3. <" . $str . ">\n\n";

这将生成以下输出:

1. <abc
#>

2. <abc
#
>

3. <abc
foo

>

如您所见,$ 匹配 12 的情况,因为 $ 匹配字符串末尾 (case 1) 或末尾的换行符之前 (case 2)。但是 case 3 仍然不匹配,因为换行符不在字符串的末尾。

【讨论】:

  • 因此,因此,无论$ 匹配,都可能没有任何内容(案例1)或只有一个换行符(案例2)。它是否正确? (显然,作为您的答案,此评论假设未设置 multiline 标志。)
  • 是的,没错,MULTILINEm 在所有 3 种情况下都没有设置。 $ 将在末尾不匹配任何内容或在末尾匹配单个换行符,这是正确的。
【解决方案2】:

“以字符串结尾的换行符”是指作为字符串最后一个字符的换行符。


没有/m

$ 匹配字符串末尾的换行符之前和字符串末尾。

"abc\ndef\n" =~ /^abc$/           # Doesn't match at embedded line feed
"abc\ndef\n" =~ /^abc\n$/         # Doesn't match after embedded line feed
"abc\ndef\n" =~ /^abc\ndef$/      # Matches at string-ending line feed
"abc\ndef\n" =~ /^abc\ndef\n$/    # Matches at end of string

相当于\Z,相当于(?=\n\z|\z)

/m

$ 匹配换行符之前和字符串末尾。

"abc\ndef\n" =~ /^abc$/           # Matches at embedded line feed
"abc\ndef\n" =~ /^abc\n$/         # Doesn't match after embedded line feed
"abc\ndef\n" =~ /^abc\ndef$/      # Matches at string-ending line feed
"abc\ndef\n" =~ /^abc\ndef\n$/    # Matches at end of string

相当于(?=\n|\z)


\z 在您想要完全匹配时使用。

/xyz\z/    # String ends with "xyz"

$ 在您想忽略尾随换行时使用。

/xyz$/     # Line ends with "xyz". The string might end with a line feed.

例如,

"jkl"   =~ /^jkl$/     # Matches at end of string
"jkl"   =~ /^jkl\z/    # Matches at end of string

"jkl\n" =~ /^jkl$/     # Matches at string-ending line feed
"jkl\n" =~ /^jkl\z/    # Doesn't match at string-ending line feed

$ 在匹配您尚未选择的行时很有用。

while (<>) {
   next if /^foo$/;
   ...
}

\z 在其余时间都很有用。


请注意,其他正则表达式引擎的行为可能不同,即使是那些类似于 Perl 的引擎。例如,在 JavaScript 中,没有/m$ 只匹配字符串的末尾。

【讨论】:

    【解决方案3】:

    关键是$ 将匹配 both 在 (a) 换行符之前以及文件或输入字符串的末尾,可以或不可以以 (a ) 换行符

    【讨论】:

      【解决方案4】:

      请查看以下代码是否有助于阐明正则表达式中$ 的含义,添加\n 以进行比较

      use strict;
      use warnings;
      use feature 'say';
      
      my $str = 'abc
      foo
      bar
      ';
      
      my $str_test;
      
      $str_test = $str;
      $str_test =~ s/(.+)$/[$1]/;
      say '-' x 30;
      say ' regex :: s/(.+)$/[$1]/';
      say '-' x 30;
      say $str_test;
      
      $str_test = $str;
      $str_test =~ s/(.+)$/[$1]/s;
      say '-' x 30;
      say ' regex :: s/(.+)$/[$1]/s';
      say '-' x 30;
      say $str_test;
      
      $str_test = $str;
      $str_test =~ s/\n/[NL]\n/s;
      say '-' x 30;
      say ' regex :: s/\n/[NL]\n/s';
      say '-' x 30;
      say $str_test;
      
      $str_test = $str;
      $str_test =~ s/\n/[NL]\n/g;
      say '-' x 30;
      say ' regex :: s/\n/[NL]\n/g';
      say '-' x 30;
      say $str_test;
      

      输出

      ------------------------------
       regex :: s/(.+)$/[$1]/
      ------------------------------
      abc
      foo
      [bar]
      
      ------------------------------
       regex :: s/(.+)$/[$1]/s
      ------------------------------
      [abc
      foo
      bar
      ]
      ------------------------------
       regex :: s/\n/[NL]\n/s
      ------------------------------
      abc[NL]
      foo
      bar
      
      ------------------------------
       regex :: s/\n/[NL]\n/g
      ------------------------------
      abc[NL]
      foo[NL]
      bar[NL]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-07-23
        • 2010-11-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-06
        相关资源
        最近更新 更多