Perl正则表达式负面后瞻

时间:2012-06-18 12:50:45

标签: regex perl negative-lookbehind

尝试在正则表达式处理中围绕前瞻后瞻

假设我有一个列出PID和其他内容的文件。我想构建一个正则表达式以匹配PID格式 \ d {1,5} ,但这也排除了某个PID。

$myself = $$;
@file = `cat $FILE`;
@pids = grep /\d{1,5}(?<!$myself)/, @file;

在这个正则表达式中,我尝试使用(?&lt;!TO_EXCLUDE)构造,使用负面后卫将数字匹配与排除相结合。这不起作用。

示例文件:

456
789
4567
345
22743
root
bin
sys

如果有人能指出我正确的方向,我将不胜感激。

也有兴趣了解这种负面观察在这种情况下是否最有效。

5 个答案:

答案 0 :(得分:6)

“看后面”真的看起来落后了。因此,您可以检查PID是否先于某些内容,而不是它是否与某些内容匹配。如果您只想排除$$,您可以更直接:

@file = `cat $FILE`;
@pids = grep /(\d{1,5})/ && $1 ne $$, @file;

答案 1 :(得分:5)

我赞成了choroba解决方案,只想解释为什么你原来的方法不起作用。

请注意,正则表达式解析器是一个复杂的野兽:它在尝试匹配尽可能多的符号时会遇到内部困难 - 并试图不惜任何代价进行匹配。而后者通常会获胜。 )

例如,让我们分析以下内容:

my $test_line = '22743';
my $pid = '22743';
print 'Matched?', "\n" if $test_line =~ /\d{1,5}(?<!$pid)/;
print $&, "\n";

为什么打印'匹配',你可能会问?因为这就是发生的事情:首先引擎试图消耗掉所有五个数字,然后匹配下一个子表达式 - 然后失败(这是负面观察点,不是吗?)

如果是你,你已经停止了 - 但不是引擎!它仍然感觉到无与伦比的黑暗欲望 - 什么!因此,它需要下一个可能的量词 - 四个而不是五个 - 当然,现在,后向子表达式注定要成功。通过检查print $&;

打印的内容,可以很容易地检查

它可以在正则表达式的范围内解决吗?是的,有所谓的atomics

print 'No match for ya!', "\n" unless $test_line =~ /(?>\d{1,5})(?<!$pid)/;

但我猜这通常被认为是一种黑魔法。 )

答案 2 :(得分:4)

如果你很好奇如何用正则表达式完成这里有一些例子:

/\b\d{1,5}+(?<!\b$pid)/

/\b\d{1,5}\b(?<!\b$pid)/

/\b(?!$pid\b)\d+/

/^(?!$pid$)\d+$/

答案 3 :(得分:2)

怎么样:

chomp(@file);      # remove newlines that will otherwise mess things up
my @pids = grep /\d{1,5}/, @file;
my %pids = map { $_ => 1 }, @pids;

delete $pids{$$};  # delete one specific pid

@pids = keys %pids;

即。通过散列汇总PID列表并删除自己的PID。需要chomp从文件中读取的行以匹配PID。

我非常确定CPAN上有一个处理流程的模块。

<强> ETA:

如果你正在阅读评论中提到的readdir中的值,那么这样的话可能是你最好的选择(未经测试):

opendir my $dh, "/proc" or die $!;
my @pids;
while ( my $line = readdir $dh ) {     # iterate through directory content
    next unless $line =~ /^\d{1,5}$/;  # skip non-numbers
    next if $line == $$;               # skip own PID
    push @pids, $line;
}

答案 4 :(得分:0)

略有不同的方式(我尽量避免使用@file = cat text.txt

my @pids;
open my $fi, "<", "pids.txt";
while (<$fi>) {
   if (/(\d{1,5})/) {
      push @pids, $1 if $1 ne $$;
   }
}
close $fi;

print join(", ", @pids), "\n";

这是我发给SO的第二篇文章,我希望可以提供另一种方法。