尝试在正则表达式处理中围绕前瞻和后瞻。
假设我有一个列出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
如果有人能指出我正确的方向,我将不胜感激。
也有兴趣了解这种负面观察在这种情况下是否最有效。
答案 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的第二篇文章,我希望可以提供另一种方法。