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";

なぜ「一致」と印刷されたのですか?それが起こったので:最初にエンジンは5つの数値すべてを消費しようとし、次に次の部分式に一致しました-そして失敗しました(それはネガティブな後ろ向きのポイントでしたね?)

それがあなたなら、あなたはすでに停止していますが、エンジンは停止していません!それでも、何の問題にもマッチしたいという暗い願望を感じています。したがって、次の可能な数量詞(5ではなく4)が必要になります。もちろん、後読み部分式は成功する運命にあります。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を削除します。chompPIDと一致するようにファイルから読み取られた行が必要です。

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;
}
于 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 への 2 回目の投稿です。別の方法を提供しても問題ないことを願っています。

于 2012-06-18T13:14:42.340 に答える