1

文字列が関連付けられている行をプルするかどうかを決定するために、特定の値の出現回数をカウントする必要がある数字の文字列の (非常に) 長いリストがあります。基本的に、ファイルは次のようにフォーマットされます。

,4,8,9,11,12,
,5,6,7,9,11,
etc.

ここで、文字列の長さの範囲は 1 ~ 100 の値、値の範囲は 1 ~ 100 で、文字列内の値は常に最小から最大の順に並べられます。

たとえば、4、9、11 の 3 つの値のうち少なくとも 2 つを含むすべての行を見つけようとしているので、正規表現を試すために書いたテスト コードを次に示します。

my $string = ",4,8,9,11,12,";

my $test = ",4,|,9,|,11,";

my @c = $string =~ m/$test/g;
my $count = @c;

print "count: $count\n";
print "\@c:, join(" ", @c), "\n";

これを実行したときの出力は次のとおりです。

count: 2
@c:,4, ,9,

count が3で @c が であると予想する場合,4, ,9, ,11,

これは、9 と 11 が同じコンマを共有しているためだと思いますが、これを回避する方法を誰かが知っているかどうか疑問に思っています。,4たとえば、を含む文字列で一致させようとする,41,と、誤って,41,.

私は次のようなことができると思います:

my $test = "4|9|11";
$string =~ s/,/ /;
my @c = $string =~ m/\b($test)\b/g

これは機能しますが、一致カウントの前に別のステップを追加します。元の文字列を変更せずに一致を実行する方法はありますか?

また、効率を最大化しようとしているため、マッチ ターゲットを個別にループして個々のマッチ カウントを合計することも避けようとしています。何百万もの順列を必要とする非常に大規模な値のリストと、現在ループを使用してスクリプトを作成している方法では、完了するのに何日もかかっています。正規表現のマッチングにより、より高速になることを願っています。

ありがとう

4

4 に答える 4

3

問題は、末尾,が一致で消費される,9,ため、次の一致を探し始めるときに11,12,. ,の前に先頭11,がないので、一致しません。次のような先読みを使用することをお勧めします。

,(4|9|11)(?=,)

このように、末尾,は一致の一部として消費されません。

例えば:

my $string = ",4,8,9,11,12,";

my $test = ",(4|9|11)(?=,)";

my @c = $string =~ m/$test/g;
my $count = @c;
print "count: $count\n";
print "\@c:", join(" ", @c), "\n";

出力:

count: 3
@c:4 9 11
于 2014-03-05T17:46:51.077 に答える
1

コンマは無視してください。これはあなたが望むことをします:

printf "count: %d\n", scalar( () = $string =~ /\b(?:4|9|11)\b/g );

() = ...空のリストへのリスト代入scalar()は、右側のリストの要素数を返すときに、 によって提供されるスカラー コンテキストで行われます。これ(?:...)は、パフォーマンスを向上させるキャプチャ グループの作成を回避するためのものです。

編集:

さて、OPはパフォーマンスを求めているので、ベンチマークを行ったところ、単純であることがわかりました

++$count while ($string =~ /\b(?:4|9|11)\b/g);

上記のリスト割り当てのトリック (古いラップトップで約 30% 高速化) および先読みパターンを使用した pswg からの回答 (約 20% 高速化) よりも高速です。

于 2014-03-05T18:09:37.963 に答える