大きなテキストファイルでは、複数の単語(「キー」と呼ばれる)を別の代替テキスト(「値」と呼ばれる)に置き換える必要があります。現在私は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
、)を使用して、JSON
CSVまたは他の構造化形式から読み込みます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演算子のみを実行するため、問題はありません。A
C
B
perl
s
また、perl
正規表現では左から右へのシフトを処理するため、入力s/\b(?:foo|foo bar)\b/$map{$&}/g
に、がある場合は代わりにfoo bar
それを置き換えます。foo
foo bar
連想配列はランダムな順序で探索されることを覚えておいてください。
sed
-E
-r
(BREを使用するか、BREで拡張正規表現をサポートする実装の場合\|
)代わりに、最長の一致を見つけようとします。
perl
を組み合わせる前に、キーを長さで並べ替えることで、同じ動作を得ることができます(例:で|
置き換えます)。keys %map
sort {length$b <=> length$a} keys %map
最後の注意:デフォルトでperl
は、入力はバイト単位で処理され、単語文字(\b
単語と単語以外の文字の境界と一致する)はASCII文字、数字、および下線に制限され、実装では通常ロケールsed
の文字セットに従ってそれをデコードしますします。入力またはキー/値にASCII以外の文字が含まれている場合は、追加してロケールの文字セットに従ってデコードできます-Mopen=locale
。または、UTF-8(現在最も一般的なロケールエンコーディング)の場合は、その-C
オプションを追加できます。