匹配不在BEGIN和END标记内部的模式

时间:2014-04-17 12:42:28

标签: regex perl

我实现了一个脚本,该脚本将检查给定正则表达式模式的文件(或多个文件),并在文件包含任何匹配项时提醒用户。但是,我希望能够允许用户在文件中指定异常(即文件中不会被检查的部分)。我想要实现这个的方式是使用BEGIN:EXCEPTION和END:文件中的EXCEPTION标记。脚本现在的工作方式如下:

(假设文件内容在$ _中)

my $re_dirty = /hello world/; # Simple example
if($re_dirty) {
    # alert that the pattern was found in the file
}

我尝试将此更改为以下内容:

my $re_dirty = /hello world/; # Simple example
my $begin_token = 'BEGIN:EXCEPTION';
my $end_token = 'END:EXCEPTION';
if($re_dirty && $_ !~ /${begin_token}.*${re_dirty}.*${end_token}) {
    # alert that the patter was found and was not in an exception block
}

然而,这有明显的问题:
1.如果模式之前和之后存在异常但模式本身不在异常中,它将匹配 2.如果模式在文件中两次,它将不匹配,但只有它们在异常块中 3.可能更多的问题??

一些澄清说明:
1.例外情况可能跨越多行 2.每个文件可以有多个异常块。

3 个答案:

答案 0 :(得分:3)

您可以在标量上下文中使用flip-flop (range operator)

if (/$begin/ .. /$end/) {
    if (/$re_dirty/) {
        # do stuff
    }
}

范围运算符的这种特殊用法将返回false(作为语句),直到左侧返回true,之后它将返回true,直到右侧返回true。

当然,使用这种方法,您应该以逐行模式读取文件。但就内存使用而言,这是一种更好的方法。

修改

如果你想匹配这些块的多行匹配 ,你首先必须将相关行收集为多行字符串:

my @outside;
my $content;
while (<$file>) {
    if ( /$begin/ .. /$end/ ) {        # if inside tags
        if (defined $content) {        # if not empty
            push @outside, $content;   # store the scalar into array
            undef $content;            # reset variable
        }
    } else {
        $content .= $_;                # store into scalar
    }
}
push @outside, $content if defined $content;

for my $portion (@outside) {
    if ($portion =~ /$re_dirty/) {     # check for multiline matches
        # do stuff
    }
}

答案 1 :(得分:1)

我会做这样的事情:

(my $portion = $_) =~ s/${begin}.*?${end}//gs; # reject anything inside begin/end blocks

if ($portion =~ $re_dirty) {
    # do stuff
}

通过这种方式,您只能获得$ part的文件相关部分(那些之外的BEGIN / END令牌)。然后你可以在相关部分进行标准的正则表达式匹配...
请注意使用&#39;?&#39;修饰符,以避免从第一个开始标记到最后结束标记的匹配...

答案 2 :(得分:0)

你可以为你的逻辑添加一个布尔值:

my $begin_token = 'BEGIN:EXCEPTION';
my $end_token = 'END:EXCEPTION';
my $bool = 0;
$bool = 1 if $begin_token;
$bool = 0 if $end_token

然后你可以测试$ bool是1还是0来跳过或不是代码的一部分