通过在perl中作为字符串传递的许多正则表来过滤列表

时间:2015-02-02 09:39:22

标签: perl

有一个存储在数组中的标签(字符串)列表。还有另一个数组,包含一些正则表达式(作为字符串)。需要通过这些正则表达式过滤标记。

以下代码是问题的演示。

#!/usr/bin/env perl
use 5.014;
use warnings;

my @re = @ARGV;
say "filters: @re";

my $line;
while(<DATA>) {
    chomp;
    $line = $_;
    my $res = checktags(@re) ? "OK" : "NO";
    say "$res for $line";
}

sub checktags {
    my(@filters) = @_;
    for my $tag (split /\s+/, $line) {  #check each tag
        for my $r (@filters) {              #with each filter
            #say "checking tag: $tag for regex: $r";
            return undef unless( $tag =~ $r );  # <--- HOW HERE???
            say "\tpassed";
        }
    }
    return 1;
}

__DATA__
aaaxxx bbb
aaa xxx bbb
aaa ccc
bbb ddd

aaa zzzbbb

E.g。用于调用脚本

perl so2.pl '/(aaa|bbb)/' '!/(xxx|zzz)/'

所以:其中一个代码必须与aaabbb 匹配,没有一个代码可以匹配xxxzzz,因此应该打印:

filters: /(aaa|bbb)/ !/(xxx|zzz)/
NO for aaaxxx bbb   #no, because one of tags matches /xxx/
NO for aaa xxx bbb  #no, as above
OK for aaa ccc      #ok, matches /aaa/ and here isn't /(xxx|zzz)/
OK for bbb ddd      #ok, as above for /bbb/
NO for              #no, no /aaa/ nor /bbb/
NO for aaa zzzbbb   #no, here is /zzz/

1 个答案:

答案 0 :(得分:0)

经过两次不同的错误逻辑尝试后,解决了以下问题:

sub checktags {
    my(@filters) = @_;
    my @tags = split /\s+/, $line;
    for my $r (@filters) {
        if( my($negate,$restr) = ( $r =~ m{^\s*(!)?/(.*)/\s*$}) ) {
            my $res = any { $_ =~ qr/$restr/ } @tags;
            return if( ($negate && $res) || (!$negate && !$res));
        }
        else {
            warn "Wrong filter $r - skipping";
        }
    }
    return @tags;
}

打印想要的内容:

filters: /(aaa|bbb)/ !/(xxx|zzz)/
NO for aaaxxx bbb
NO for aaa xxx bbb
OK for aaa ccc
OK for bbb ddd
NO for 
NO for aaa zzzbbb