Perl正则表达式无意中似乎正在修改源String

时间:2013-11-14 12:45:13

标签: regex perl

尝试匹配Perl程序中某个文件的某些数据模式。由于匹配可能超过多行,因此我将行分隔符设置为未定义。

$/ = undef ;

现在,因为匹配可以跨越多行而不止一行,所以我使用了smgi修饰符。

if ( $msgText =~ /$msgTypeExpr/smgi )

现在,我遇到的问题是上面的变量$ msgText被修改了,虽然我没有替换它。

以下是相关代码:

open (HANDLE1,"$file") || die "cannot open file \n";
$/ = undef ;
while ( my $msgText = <HANDLE1> )
{
        my $msgTypeExpr = "<city\\W+";

        print "Attempt 1:\n";
        if ( $msgText =~ /$msgTypeExpr/smgi )
        {
                print "matched\n";
        }
        else
        {
                print " not matched \n";
        }

        print "Attempt 2:\n";
        if ( $msgText =~ /$msgTypeExpr/smgi )
        {
                print "matched\n";
        }
        else
        {
                print " not matched \n";
        }
}

测试输入文件如下所示:

<city
 name="abc">
</city>

人们会期望模式匹配两次但它只匹配第一次而不是第二次匹配。

我暂时解决了这个问题,在匹配和使用该temp变量匹配之前,暂时分配一个临时变量。

my $tmpMsgText = $msgText ;

这是我第一次在这个论坛上发帖提问,所以请原谅我所犯的任何礼仪错误,也请你好好指出,以便我将来不再重复。

2 个答案:

答案 0 :(得分:2)

首先,我不确定是否会阅读这样的文件。修改那些Perl特殊变量,比如$ /应该用local来完成,如下所示:

local $/ = undef;

这样,变量仅在当前范围内进行修改(从而消除了可能的远距离错误)。通过将$ /设置为undef,您将一次性读取整个文件,因此没有必要在其中放置while循环。我会像这样阅读整个文件:

open my $fh, "<", "somefile" or die;
my $content = do { local $/ = undef; <$fh> };

do块仅将修改后的$ / value限制为该一个语句(它创建一个新范围)。

关于正则表达式匹配:在正则表达式后删除/ g修饰符。如果我没记错的话,它会记住最后一个正则表达式搜索位置并从那里继续。同样,为了检测字符串是否被更改,请在这些匹配之前和之后打印变量。你会看到,他们没有被修改。 而不是:

if ( $msgText =~ /$msgTypeExpr/smgi )

放:

if ( $msgText =~ /$msgTypeExpr/smi )

答案 1 :(得分:2)

if (//g)毫无意义。 “如果它匹配并继续匹配,直到没有匹配”?摆脱g

我不知道你为什么使用sm

s没用,因为该模式不包含.

m没用,因为该模式不包含^$


实际上,标量上下文中的//g充当迭代器。

$ perl -E'$_ = "abc"; /(.)/g && say $1; /(.)/g && say $1;'
a
b