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

时间:2009-12-04 16:47:47

标签: regex perl

What regular expressions can never match? /$./作为回复。我玩了一下,发现以下两行代码产生不同的输出。第二场比赛,但第一场比赛没有。任何人都可以解释原因吗?

$ printf 'a\nb\n' | perl -0777 -ne 'print if m/$./m'
$ perl -0777 -e '$_="a\nb\n"; print if m/$./m'

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

$ 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'

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

4 个答案:

答案 0 :(得分: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

您在正则表达式中使用了未定义的值。序列$. refers to the special variable for the line number of the last-accessed file handle指定“行尾后跟任何字符”的正则表达式。由于您还没有访问任何文件,它仍然是undef,所以正则表达式是空的。当您使用-n选项时,它会有效地将该计划的其余部分包含在while (<>) { ... }中,因此您在<>中阅读1并以$.结尾,因为你读过一行。

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

答案 1 :(得分:6)

正则表达式中的$.被解析为特殊变量$.$INPUT_LINE_NUMBER)的值,而不是“行尾后跟任何字符。”

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

say "a\nb\n" =~ m/$ ./msx;

打印“1”。 /x修饰符允许使用嵌入的空格,因此我们可以将$.分开,以避免将其解释为变量。

答案 2 :(得分: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'

以下代码读取管道数据,但不匹配,因为$.<>之后变为等于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'

<强>更新

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

答案 3 :(得分:0)

在第一个例子中,我认为这是因为-n开关。换句话说

printf 'a\nb\n' | perl -0777 -ne 'print if m/$./m'

导致$ _第一次通过循环获得值a\n,第二次b\n使得m/$./m无法匹配。而/ m $匹配第二个示例中的\ n,这就是匹配的原因。

在后两个例子中,我仍然在研究:)

编辑:哇我完全错了,我想你也可能。问题是{{1}} 不是行尾,后跟通配符,而是变量$。插值为正则表达式。糟糕!