从`s/^/1 /;`中删除`^`导致我的代码失败.为什么?

hma*_*tt1 5 regex perl

我一直在代码高尔夫交易所处理这个问题,这就是为什么我的代码看起来很有趣.

这是一个程序,use strictuse warnings重新创建问题:

use strict;
use warnings;

$_ = "";

for my $i (1..33){
    s//1/;   # Just prepends 1 to the string $_
}
print "$_\n";

for my $i (34..127) {
    if( chr(y/1/1/) !~ /[!"'()*+,-.\/12357:;<=>?CEFGHIJKLMNSTUVWXYZ[\\\]^_`cfhijklmnrstuvwxyz{|}~]/ ) {
        print chr y/1/1/;
    }
    s/^/1/;   # Prepends 1 to the start of the string.
}
Run Code Online (Sandbox Code Playgroud)

这是输出:

111111111111111111111111111111111
#$%&04689@ABDOPQRabdegopq
Run Code Online (Sandbox Code Playgroud)

这可以像我期望的那样工作.但是,当我^取出第二个正则表达式时,正则表达式不再匹配和延长字符串.

use strict;
use warnings;

$_ = "";

for my $i (1..33){
    s//1/;
}
print "$_\n";

for my $i (34..127) {
    if( chr(y/1/1/) !~ /[!"'()*+,-.\/12357:;<=>?CEFGHIJKLMNSTUVWXYZ[\\\]^_`cfhijklmnrstuvwxyz{|}~]/ ) {
        print chr y/1/1/;
    }
    s//1/;   # No Longer matches!
}
Run Code Online (Sandbox Code Playgroud)

为什么会这样?s//1/在第一个循环中工作,那么为什么在第二个循环中更改它会破坏一切?

另外还有一点困惑,如果你把if块放在大括号中,那么正则表达式会再次匹配:

for my $i (34..127) {
    {
        if( chr(y/1/1/) !~ /[!"'()*+,-.\/12357:;<=>?CEFGHIJKLMNSTUVWXYZ[\\\]^_`cfhijklmnrstuvwxyz{|}~]/ ) {
            print chr y/1/1/;
        }
    }
    s//1/;   # This prepends 1 to the string $_ again.
}
Run Code Online (Sandbox Code Playgroud)

编辑:

我想将原始代码编辑回问题以供参考:

use strict;
use warnings;
$_="";
until( y/1/1/ > 32){
    print "test1";
    s//1/;
    print "test";
}
print "$_\n";
until( y/1/1/ > 125+1 ) {
    if( chr(y/1/1/) !~ /[!"'()*+,-.\/12357:;<=>?CEFGHIJKLMNSTUVWXYZ[\\\]^_`cfhijklmnrstuvwxyz{|}~]/ ) {
        print chr y/1/1/;
    }

    s/^/1/; # this is the line we remove ^ from
}
Run Code Online (Sandbox Code Playgroud)

当我们^从该行中删除时,输出将从:

test1testtest1testtest1testtest1testtest1testtest1testtest1testtest1testtest1testtest1testtest1testtest1testtest1testtest1testtest1testtest1testtest1testtest1testtest1testtest1testtest1testtest1testtest1testtest1testtest1testtest1testtest1testtest1testtest1testtest1testtest1testtest1testtest1test111111111111111111111111111111111
#$%&04689@ABDOPQRabdegopq
Run Code Online (Sandbox Code Playgroud)

挂着没有输出

所以在这种情况下,第二个循环中的换行会改变它看起来的第一个行为.

小智 5

s//1/;不检查任何或空字符串.它检查之前的最后一个成功的正则表达式文本.因此,第一个循环使用默认正则表达式,第二个循环使用if上面的最后一次成功检查.

引用:

如果PATTERN求值为空字符串,则使用最后成功匹配的正则表达式.在这种情况下,只有空模式上的g和c标志才会被遵守

请看空模式//

  • 有趣的是,但这不是一个充分的解释.如果将正则表达式更改为:`s // ^ /; 打印"$ i $ _ \n";`,可以观察到正则表达式匹配并修改`$ _`,但更改不会在循环中持续存在.另外,这并没有解释`if`语句周围的额外括号消除了这个错误. (2认同)

opt*_*nal 2

扩展弗拉基米尔的答案

print "regex have dynamic scope\n";
$_ = 1;
{
    m/1/;
    s//2/;
    print "$_  one becomes two, s//2/ is really s/1/2/\n";
}
$_=1;
{
    m/1/;
    {
        s//2/;
    }
    print "$_  one still becomes two, s//2/ is really s/1/2/\n";
}

$_=1;
{
    {
        m/1/;
    }
    s//2/;
    print "$_  one becomes twentyone, s//2/; is really s/(?:)//2;\n";
}

__END__
regex have dynamic scope
2  one becomes two, s//2/ is really s/1/2/
2  one still becomes two, s//2/ is really s/1/2/
21  one becomes twentyone, s//2/; is really s/(?:)//2;
Run Code Online (Sandbox Code Playgroud)

由于正则表达式具有动态范围,因此使用空模式 //实际上意味着使用同一动态范围中的先前模式,所以不要这样做:)

如果添加,use re 'debug';您可以看到正则表达式引擎使用先前的模式(重点关注Matching REx语句,NOTHING(2)没有前一个为空,EXACT <1>(3)是先前的模式)

regex have dynamic scope
Guessing start of match in sv for REx "1" against "1"
Found anchored substr "1" at offset 0...
Guessed: match at offset 0
Guessing start of match in sv for REx "1" against "1"
Found anchored substr "1" at offset 0...
Guessed: match at offset 0
Matching REx "1" against "1"
   0 <> <1>                  |  1:EXACT <1>(3)
   1 <1> <>                  |  3:END(0)
Match successful!
2  one becomes two, s//2/ is really s/1/2/
Guessing start of match in sv for REx "1" against "1"
Found anchored substr "1" at offset 0...
Guessed: match at offset 0
Guessing start of match in sv for REx "1" against "1"
Found anchored substr "1" at offset 0...
Guessed: match at offset 0
Matching REx "1" against "1"
   0 <> <1>                  |  1:EXACT <1>(3)
   1 <1> <>                  |  3:END(0)
Match successful!
2  one still becomes two, s//2/ is really s/1/2/
Guessing start of match in sv for REx "1" against "1"
Found anchored substr "1" at offset 0...
Guessed: match at offset 0
Matching REx "" against "1"
   0 <> <1>                  |  1:NOTHING(2)
   0 <> <1>                  |  2:END(0)
Match successful!
21  one becomes twentyone, s//2/; is really s/(?:)//2;
Run Code Online (Sandbox Code Playgroud)

更新:因为你有一个无限循环;最后一个模式总是有 1,所以替换本质上是 s/1/1/;这意味着你的字符串不会增长,它总是 33 个字符......请参阅更新:)

$_="";
until( y/1/1/ > 32){
    print "test1";
    s//1/;
    print "test";
}
print "$_\n";
my $max = 126;
my $count = 0;
my $reps = 0;
until( y/1/1/ > 125+1 ) {
    if( chr(y/1/1/) !~ /[!"'()*+,-.\/12357:;<=>?CEFGHIJKLMNSTUVWXYZ[\\\]^_`cfhijklmnrstuvwxyz{|}~]/ ) {
        print chr y/1/1/;
    }
$reps =
#~     s/^/1/; # win
    s//1/; # fail
    $count++;
    last if $count > $max;
}
print "m $max c $count r $reps l @{[ length $_ ]}\n";
__END__
win #$%&04689@ABDOPQRabdegopqm 126 c 94 r 1 l 127
fail m 126 c 127 r 1 l 33
Run Code Online (Sandbox Code Playgroud)

除非你混淆了append is$_ .= 1;和prepend is$_ = 1 . $_;