コマンドラインのファイルから複数の文字列を削除する、高性能[閉じる]

コマンドラインのファイルから複数の文字列を削除する、高性能[閉じる]

入力から複数の完全な文字列を削除するエレガントでパフォーマンスに優れた1行の方法はありますか?

私は100万行ほどの大容量テキストファイルを扱います。入力ファイルと100,000の一致する文字列ヒットファイル。 Perlスクリプトをロードしました。ヒットファイルハッシュに入れて、各行のすべての「単語」を確認してください。入力ファイルしかし、私のワークフローでは、スクリプトではなく単純なコマンドを好みます。

私が探している機能は次のとおりです。

perl -pe 's/\b(string1|string2|string3)\b)//g' 

または、ネストされた sed を使用するこのアプローチは次のとおりです。

sed -e "$(sed 's:.*:s/&//ig:' hitfile)" inputfile

またはシェルで繰り返します。

while read w; do sed -i "s/$w//ig" hitfile ; done < inputfile

しかし、それは高すぎます。このやや効率的なアプローチが効果的です(テキストファイルから単語リストのすべての項目を削除するには?)しかしまだ遅いです。

perl -Mopen=locale -Mutf8 -lpe '
  BEGIN{open(A,"hitfile"); chomp(@k = <A>)} 
  for $w (@k){s/(^|[ ,.—_;-])\Q$w\E([ ,.—_;-]|$)/$1$2/ig}' inputfile

しかし、これをより簡潔にするための別のトリックはありますか?私が見落としている他のUnixコマンドや方法はありますか?正規表現は必要ありません。純粋/正確な文字列をハッシュ(速度のため)と比較するだけです。つまり、「pine」は「pineapple」と一致してはいけませんが、「(pine)」と一致する必要があります。

たとえば、私のアイデアの1つは、ファイル内の単語を別々の行に拡張することでした。

今後:

Hello, world!

後ろに:


Hello
, 
world
!

次に、grep -vfを使用して行を処理し、再構築/接続します。

他の速くて簡単なアイデアはありませんか?

答え1

あなたのものは正確にどのくらい大きいですかhitfile?あなたがしたいことのいくつかの実際的な例を示すことができますか?入力データの詳細を提供していないので、これは次のようになります。ただ考える試してみて実際のデータのベンチマーク

Perl正規表現はかなり大きくなる可能性があり、単一の正規表現を使用すると、入力ファイルを一度に変更できます。ここでは、/usr/share/dict/words巨大な正規表現を作成する例として使用しています。正規表現には約99,000本のラインがあり、サイズは約1MBです。

use warnings;
use strict;
use open qw/:std :encoding(UTF-8)/;

my ($big_regex) = do {
    open my $wfh, '<', '/usr/share/dict/words' or die $!;
    chomp( my @words = <$wfh> );
    map { qr/\b(?:$_)\b/ } join '|', map {quotemeta}
        sort { length $b <=> length $a or $a cmp $b } @words };

while (<>) {
    s/$big_regex//g;
    print;
}

正規表現は必要ありません。純粋/正確な文字列をハッシュ(速度のため)と比較するだけです。つまり、「pine」は「pineapple」と一致してはならず、「(pine)」と一致しなければなりません。

「pine」が「pineapple」と一致しない場合は、入力に「pine」が表示される前後の文字も確認する必要があります。固定文字列アプローチを使用することは確かに可能ですが、単語の境界に関する正規表現の概念のように聞こえます(\b)あなたが求めているものです。

エレガントでパフォーマンスに優れた1行の方法はありますか?私のワークフローでは、スクリプトよりも単純なコマンドを好みます。

私はその感情に同意するかどうかわからない。質問がありますかperl script.pl? 1行のコードのように、シェルリダイレクト/パイピングで使用できます。コードをスクリプトに配置すると、コマンドラインが整理され、すべてを1行のコードにまとめることなく複雑な作業を実行できます。また、短いからといって必ずしも速いわけではありません。

スクリプトを使用するもう1つの理由は、入力ファイルが複数ある場合です。上記のコードを使用すると、正規表現を書くのに費用がかかるため、スクリプトを複数回呼び出すのに費用がかかります。単一のスクリプトで複数のファイルを処理すると、そのオーバーヘッドが削除されます。私はUNIXの原則が好きですが、ビッグデータの場合は、複数のプロセスを呼び出す(時には複数回)、プロセス間でデータをパイピングすることは常に最も効率的なアプローチではなく、単一のプログラムですべてを単純化するのに役立ちます。


修正する:コメントによると、ロープは自分の足を撃つのに十分です。

関連情報