为什么m /$./ m会给我意想不到的行为?

Wil*_*ell 0 regex perl

什么正则表达式永远不会匹配? /$./作为回应.我玩了一下,发现以下两行代码产生不同的输出.第二场比赛,但第一场比赛没有.有谁能解释为什么?

$ printf 'a\nb\n' | perl -0777 -ne 'print if m/$./m'
$ perl -0777 -e '$_="a\nb\n"; print if m/$./m'
Run Code Online (Sandbox Code Playgroud)

另请注意,在下面添加<>会导致匹配失败:

$ printf 'a\nb\n' | perl -0777 -e '$b = "a\nb\n"; say $b =~ m/$./m'
$ printf 'a\nb\n' | perl -0777 -e '$b = "a\nb\n"; <>; say $b =~ m/$./m'
Run Code Online (Sandbox Code Playgroud)

(也就是说,第一次打印'1',第二次打印空白行)

Rob*_*edy 9

打开警告提供了一个原因的线索:

$ printf 'a\nb\n' | perl -0777 -w -e 'use feature qw/say/; $b = "a\nb\n"; say $b =~ m/$./m'
Use of uninitialized value $. in regexp compilation at -e line 1.
1

您正在使用正则表达式中的未定义值.序列$.引用最后访问的文件句柄的行号的特殊变量.它并没有指定正则表达式"线后跟任意字符的结束".由于您还没有访问任何文件,它仍然是undef,所以正则表达式是空的.当您使用该-n选项时,它会有效地包装程序的其余部分while (<>) { ... },因此您阅读<>并最终结束1,$.因为您已阅读一行.

当你<>在第二次尝试时说,你已经访问了stdin文件句柄.现在正则表达式是m/1/m,与输入字符串不匹配.


Mic*_*man 6

$.您的正则表达式被解析为特殊变量的值$.($INPUT_LINE_NUMBER),而不是"行后跟任意字符的结束."

另请注意,/m修饰符会更改$字符串末尾匹配的含义,以及匹配字符串中任何位置的行结尾.请参阅perlre中的修饰符.这意味着可以在它之后有一些东西(使用适当的修饰符):

say "a\nb\n" =~ m/$ ./msx;
Run Code Online (Sandbox Code Playgroud)

打印"1".所述/x改性剂允许使用嵌入空白的,所以我们可以分离$.以避免它被解释为一个可变.


Iva*_*uev 5

这段代码为我打印"破管",因为perl不希望这里有任何输入.它还使用未定义的变量$.(如果你将-w开关添加到perl,你会看到它).此变量$.表示当前行号,然后读取行数<...>.这就是为什么它在这个例子中未定义:

## matching pattern will look like m//m
printf 'a\nb\n' | perl -0777 -e '$b = "a\nb\n"; say $b =~ m/$./m'
Run Code Online (Sandbox Code Playgroud)

下面的代码读取管道数据,但不会匹配,因为之后$.变为等于1 <>.匹配模式变为m/1/m:

## matching patter will be m/1/m, which is not found in $b value
printf 'a\nb\n' | perl -0777 -e '$b = "a\nb\n"; <>; say $b =~ m/$./m'
Run Code Online (Sandbox Code Playgroud)

更新:

使用m'$.'mm/$ ./mx(感谢Michael Carman)禁用变量插值.