正则表达式作为命令行arg用于过滤具有特定值的行

时间:2012-03-12 20:56:16

标签: regex perl

我希望能够从命令行中获取一个参数,并将其用作我脚本中的正则表达式来过滤我文件中的行。一个简单的例子

$ perl script.pl id_4

在script.pl中:

...
my $exp = shift;
while(my $line = <$fh){
    if($line =~ /$exp/){
        print $line,"\n";
    }
}
...

我的实际脚本有点复杂,并且对该行进行其他操作以提取信息并生成不同的输出。我的问题是我想要过滤掉包含“id_4”的每一行,而不是仅包含“id_4”的选择行。通常这可以通过

来实现
if($line !~ /$exp/)

但是,如果可能的话,我不想改变我的脚本以接受更复杂的参数集(例如,如果第二个参数是“ne”,则使用!~,如果不是,则使用=~

任何人都可以想到我可以使用的正则表达式(除了长“id_1 | id_2 | id_3 | id_5 ...”之外)从多种可能性中过滤掉包含一个特定值的行吗?我担心我在这里要求愚蠢,应该坚持理智并接受进一步的论证:/。

2 个答案:

答案 0 :(得分:1)

为什么选择?有两个。

my $exp = join "|", grep !/^!/, @ARGV;
my @not = grep /^!/,  @ARGV;
s/^!// for @not;
my $exp_not = join "|", @not;

...
if (( $line =~ $exp ) && ( $line !~ $exp_not )) {
    # do stuff
}

<强>用法:

perl script.pl orange soda !light !diet

答案 1 :(得分:0)

有一种方法可以反转正则表达式,因此您可以执行匹配,例如“所有不包含subexpr匹配的字符串”。如果没有直接表达这一点的运算符(即仅使用基本的正匹配正则表达式运算符),它仍然可能会导致大而笨重的正则表达式(可能是正则表达式大小中的组合爆炸)。

举一个简单的例子,看看我对这个问题的回答:如何编写一个匹配除字符串“help”之外的所有内容的正则表达式。 (这是一个相当简化的比赛,以匹配开始和结束。)Match all letter/number combos but specific word?

当您想要将表达式的匹配反转为整体时,传统的Unix工具会出现问题:grepgrep -v。或者vi:g/pat/:v/pat/等等。通过这种方式,实现者避免了实现不适合简单NFA构造方法的困难正则表达式运算符。

最简单的事情就是做同样的事情并且有一个粗粒度否定的约定:包含模式和排除模式。