辞書を使用してファイル内の文字列置換を実行する良い方法は何ですかたくさん置換末端置換基対?そしてたくさん、実際には20個程度を意味します。多くはありませんが、きれいに整理したいほど十分です。
dictionary.txt
次のような多くの項目を置き換える必要があるため、管理可能な方法ですべての置換された最終置換基のペアをファイルに収集したいと思います。
"yes" : "no"
"stop" : "go, go, go!"
"wee-ooo" : "ooooh nooo!"
"gooodbye" : "hello"
"high" : "low"
"why?" : "i don't know"
今、特定のファイルにこれらの代替項目を適用したいと思いますnovel.txt
。
その後、inのすべてのインスタンスが置き換えられ(それでEvenが置き換えられます)、inのすべてのインスタンスが置き換えられるmagiccommand --magicflags dictionary.txt novel.txt
ように実行しようとします。yes
novel.txt
no
Bayesian
Banoian
goodbye
novel.txt
hello
これまでに置き換える必要がある文字列は次のとおりです。いいえその中に引用符があります(一重引用符や二重引用符ではありません)。 (もちろん、引用符付きの文字列をうまく処理する解決策を見るとよいでしょう。)
私も知っていてsed
/ awk
maingawk
もこれを行うことができますが、このような辞書ファイルも使用できますか?gawk
適切な候補者のようですmagiccommand
。適切な候補者は誰ですかmagicflags
?どのようにフォーマットする必要がありますかdictionary.txt
?
答え1
方法は次のとおりですsed
。
sed '
s|"\(.*\)"[[:blank:]]*:[[:blank:]]*"\(.*\)"|\1\
\2|
h
s|.*\n||
s|[\&/]|\\&|g
x
s|\n.*||
s|[[\.*^$/]|\\&|g
G
s|\(.*\)\n\(.*\)|s/\1/\2/g|
' dictionary.txt | sed -f - novel.txt
仕組み:
最初のファイルはスクリプトファイルにsed
なります(編集コマンド、1行に1つ)。dictionary.txt
これは、これらのコマンドを実行する2番目のコマンドsed
(注:これは-f -
読み取りコマンドを意味しますstdin
)、editにパイプされますnovel.txt
。
形式を翻訳する必要があります。
"STRING" : "REPLACEMENT"
コマンドに入れて、sed
プロセス内のすべての特殊文字をエスケープしますLHS
。RHS
s/ESCAPED_STRING/ESCAPED_REPLACEMENT/g
だから最初の交換
s|"\(.*\)"[[:blank:]]*:[[:blank:]]*"\(.*\)"|\1\
\2|
(改行文字です)になります"STRING" : "REPLACEMENT"
。次に、結果を前のスペースにコピーします。最初の部分を削除し、予約文字(これは)のみを保持してからエスケープします。次に、パターンスペースを使用して保持バッファを変更し、保持された2番目の部分のみを削除してエスケープします(つまり)。その後、バッファの内容はパターン空間に追加されたままになるので、パターン空間の内容は 。最終交換STRING\nREPLACEMENT
\n
h
s|.*\n||
REPLACEMENT
s|[\&/]|\\&|g
RHS
x
s|\n.*||
STRING
s|[[\.*^$/]|\\&|g
LHS
G
ESCAPED_STRING\nESCAPED_REPLACEMENT
s|\(.*\)\n\(.*\)|s/\1/\2/g|
それに変換するs/ESCAPED_STRING/ESCAPED_REPLACEMENT/g
答え2
これはPerlバージョンです。プリコンパイルされた正規表現を含むハッシュを生成し、各入力行を繰り返してすべての正規表現を各行に適用します。入力ファイルの「内部編集」用perl
です。-i
正規表現または置換文字列を簡単に追加または変更できます。
プリコンパイルされた正規表現を使用すると、qr//
スクリプトの速度が大幅に向上します。これは、処理する正規表現および/または入力行数が多い場合に顕著に向上します。
#! /usr/bin/perl -i
use strict;
# the dictionary is embedded in the code itself.
# see 2nd version below for how to read dict in
# from a file.
my %regex = (
qr/yes/ => 'no',
qr/stop/ => 'go, go, go!',
qr/wee-ooo/ => 'ooooh nooo!',
qr/gooodbye/ => 'hello',
qr/high/ => 'low',
qr/why\?/ => 'i don\'t know',
);
while (<>) {
foreach my $key (keys %regex) {
s/$key/$regex{$key}/g;
}
}
以下は、コマンドラインの最初のファイル名から辞書を読み取ると同時に2番目(およびオプションで後続)のファイル名を処理する別のバージョンです。
#! /usr/bin/perl -i
use strict;
# the dictionary is read from a file.
#
# file format is "searchpattern replacestring", with any
# number of whitespace characters (space or tab) separating
# the two fields. You can add comments or comment out dictionary
# entries with a '#' character.
#
# NOTE: if you want to use any regex-special characters as a
# literal in either $searchpattern or $replacestring, you WILL
# need to escape them with `\`. e.g. for a literal '?', use '\?'.
#
# this is very basic and could be improved. a lot.
my %regex = ();
my $dictfile = shift ;
open(DICT,'<',$dictfile) || die "couldn't open $dictfile: $!\n";
while(<DICT>) {
s/#.*// unless (m/\\#/); # remove comments, unless escaped.
# easily fooled if there is an escaped
# '#' and a comment on the same line.
s/^\s*|\s*$//g ; # remove leading & trailing spaces
next if (/^$/) ; # skip empty lines
my($search, $replace) = split;
$regex{qr/$search/} = $replace;
};
close(DICT);
# now read in the input file(s) and modify them.
while (<>) {
foreach my $key (keys %regex) {
s/$key/$regex{$key}/g;
}
}
答え3
これをコメントとして書き始めましたが、複雑すぎて2番目のPerl回答があります。ソースファイルが与えられたら、きちんとしたPerlトリックを使って正規表現を書くことができます。
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
#build key-value pairs
my %replace = map { /"(.+)"\s*:\s*"(.+)"/ } <DATA>;
print Dumper \%replace;
#take the keys of your hash, then build into capturing regex
my $search = join ( "|", map {quotemeta} keys %replace );
$search = qr/($search)/;
print "Using match regex of: $search\n";
#read stdin or files on command line, line by line
while ( <> ) {
#match regex repeatedly, replace with contents of hash.
s/$search/$replace{$1}/g;
print;
}
__DATA__
"yes" : "no"
"stop" : "go, go, go!"
"wee-ooo" : "ooooh nooo!"
"gooodbye" : "hello"
"high" : "low"
"why?" : "i don't know"
map
ハッシュを生成し、キーと値のペアを生成するには、複数行のパターンマッチングを使用します。
検索正規表現を作成し、ここでキャプチャされた値に置き換えます。
使用されるのは、<>
PerlのマジックファイルハンドルSTDIN
またはコマンドラインで指定されたファイルです。 sedはこれをどのように実行しますか? (ファイルを使用してそのスキーマを「一般的に」読むことができます。使用法はDATA
純粋に説明のためのものです。)