大きなテキストファイルに複数回表示される「キー」を対応する代替「値」に置き換えます。

大きなテキストファイルに複数回表示される「キー」を対応する代替「値」に置き換えます。

大きなテキストファイルでは、複数の単語(「キー」と呼ばれる)を別の代替テキスト(「値」と呼ばれる)に置き換える必要があります。現在私はsedこの目的のために次のようなものを使います。

sed -i -e 's/\bkey\b/value/' file

ファイルが大きく、プロセスに数分かかります。 1,000を超えるキーと値のペアがあり、現在sed各キーと値のペアに対してプロセスを繰り返しています。明らかにこれは長い時間がかかります。

一度に(またはより速く)交換を実行できるように、「Key-Value」(パターン交換)ペアセットをsed/または同様のユーティリティに入力する方法があるかどうか疑問に思います。awkキーと値のペアは任意の形式で構成できます。

たとえば、名前を略語(TSV形式など)に変更します。

Key                                               Value
United Nations                                    UN
United States Environmental Protection Agency     EPA
International Atomic Energy Agency                IAEA
World Health Organization                         WHO

入力テキストは次のとおりです。

これは国連と世界保健機関(WHO)が報告した内容です。これがIAEAの主な分野です。米国環境保護局は、この問題を監督する連邦機関です。

ベストアンサー1

ここでは-i両方とも\bいくつかのsed実装ですperl。まず、以下を使用することをお勧めしますperl

perl -i -pe '
  BEGIN {
    %map = (
      "key1"  => "value1",
      "key 2" => "value2"
    );
    $re = join "|", map {qr{\Q$_\E}} keys %map;
  }
  s/\b(?:$re)\b/$map{$&}/g' your-file

キー => 値マッピングは、次のように表現することもできます。

%map = qw(
   key1 value1
   key2 value2
);

または、対応するperlモジュール(Text::CSV、)を使用して、JSONCSVまたは他の構造化形式から読み込みますperl。テキスト操作に適した汎用プログラミング言語なので、ここでは明確な選択であり、実行できる操作に制限はありません。 。

単純なTSVの場合は、次のようになります。

<map.tsv perl -i -pe '
  BEGIN {
    <STDIN>; # skip header
    while (<STDIN>) {
      chomp;
      my ($k, $v) = split /\t/;
      $map{$k} = $v;
    }

    $re = join "|", map {qr{\Q$_\E}} keys %map;
  }
  s/\b(?:$re)\b/$map{$&}/g' your-file

次の作業を行う場合は注意してください。

sed -i -e 's/\bK1\b/V1/g' file
sed -i -e 's/\bK2\b/V2/g' file

次のように単純化できます。

sed -i '
  s/\bK1\b/V1/g
  s/\bK2\b/V2/g' file

またはTSVの場合:

<map.tsv awk -F'\t' '
   NR > 1 {
     # escape regexp operators in keys to emulate perl \Q \E:
     gsub(/[][\/\\*.^$]/, "\\\\&", $1)
     # escape /, \ and & in replacement:
     gsub(/[\\/&]/, "\\\\&", $2)
     print "s/\\b"$1"\\b/"$2"/g"
   }' | sed -i -f - your-file

ファイルを一度だけ読み書きします。

ただし、いずれの場合も一部の場合価値その中でも。たとえば、s/\bA\b/B/gヒールを使用すると、sの代わりにsがs/\bB\b/C/g表示されます。上記の方法はubtitute演算子のみを実行するため、問題はありません。ACBperls

また、perl正規表現では左から右へのシフトを処理するため、入力s/\b(?:foo|foo bar)\b/$map{$&}/gに、がある場合は代わりにfoo barそれを置き換えます。foofoo bar

連想配列はランダムな順序で探索されることを覚えておいてください。

sed-E-r(BREを使用するか、BREで拡張正規表現をサポートする実装の場合\|)代わりに、最長の一致を見つけようとします。

perlを組み合わせる前に、キーを長さで並べ替えることで、同じ動作を得ることができます(例:で|置き換えます)。keys %mapsort {length$b <=> length$a} keys %map

最後の注意:デフォルトでperlは、入力はバイト単位で処理され、単語文字(\b単語と単語以外の文字の境界と一致する)はASCII文字、数字、および下線に制限され、実装では通常ロケールsedの文字セットに従ってそれをデコードしますします。入力またはキー/値にASCII以外の文字が含まれている場合は、追加してロケールの文字セットに従ってデコードできます-Mopen=locale。または、UTF-8(現在最も一般的なロケールエンコーディング)の場合は、その-Cオプションを追加できます。

おすすめ記事