3

试图在正则表达式处理中围绕前瞻后视。

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

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

在这个正则表达式中,我尝试使用(?<!TO_EXCLUDE)构造将数字匹配与排除相结合。这行不通。

示例文件:

456
789
4567
345
22743
root
bin
sys

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

也有兴趣了解在这种情况下这种消极的后视是否是最有效的。

4

5 回答 5

6

“往后看”真的是往后看。因此,您可以检查 PID 前面是否有某些东西,而不是它是否匹配某些东西。如果您只想排除 $$,您可以更直接:

@file = `cat $FILE`;
@pids = grep /(\d{1,5})/ && $1 ne $$, @file;
于 2012-06-18T12:59:30.933 回答
5

我赞成 choroba 解决方案,只是想解释为什么您的原始方法不起作用。

看,正则表达式解析器是一头复杂的野兽:它在尝试匹配尽可能多的符号的内部斗争中遭受痛苦 - 并且不惜一切代价尝试匹配。后者,嗯,通常会赢。)

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

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

您可能会问,为什么它会打印“匹配”?因为这就是发生的事情:首先引擎尝试使用所有五个数字,然后匹配下一个子表达式 - 并且失败了(那是消极的后视点,不是吗?)

如果是你,你已经停止了 - 但不是引擎!还是觉得那阴暗的欲望,无论如何都要匹配!所以它需要下一个可能的量词 - 四个而不是五个 - 现在,当然,lookbehind 子表达式注定要成功。) 这很容易通过检查print $&;打印的内容来检查。

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

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

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

于 2012-06-18T13:19:02.100 回答
4

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

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

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

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

/^(?!$pid$)\d+$/
于 2012-06-18T13:17:45.893 回答
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 上有一个模块可以处理进程。

预计到达时间:

如果您正在阅读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;
}
于 2012-06-18T13:17:45.530 回答
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 的第二篇文章,我希望可以提供另一种方法。

于 2012-06-18T13:14:42.340 回答