文字列を置き換えるには辞書を使用してください。

文字列を置き換えるには辞書を使用してください。

辞書を使用してファイル内の文字列置換を実行する良い方法は何ですかたくさん置換末端置換基対?そしてたくさん、実際には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ように実行しようとします。yesnovel.txtnoBayesianBanoiangoodbyenovel.txthello

これまでに置き換える必要がある文字列は次のとおりです。いいえその中に引用符があります(一重引用符や二重引用符ではありません)。 (もちろん、引用符付きの文字列をうまく処理する解決策を見るとよいでしょう。)

私も知っていてsed/ awkmaingawkもこれを行うことができますが、このような辞書ファイルも使用できますか?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プロセス内のすべての特殊文字をエスケープしますLHSRHS

s/ESCAPED_STRING/ESCAPED_REPLACEMENT/g

だから最初の交換

s|"\(.*\)"[[:blank:]]*:[[:blank:]]*"\(.*\)"|\1\
\2|

(改行文字です)になります"STRING" : "REPLACEMENT"。次に、結果を前のスペースにコピーします。最初の部分を削除し、予約文字(これは)のみを保持してからエスケープします。次に、パターンスペースを使用して保持バッファを変更し、保持された2番目の部分のみを削除してエスケープします(つまり)。その後、バッファの内容はパターン空間に追加されたままになるので、パターン空間の内容は 。最終交換STRING\nREPLACEMENT\nh
s|.*\n||REPLACEMENTs|[\&/]|\\&|gRHS
xs|\n.*||STRINGs|[[\.*^$/]|\\&|gLHS
GESCAPED_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純粋に説明のためのものです。)

関連情報