代替リストのテキストを置き換えます。複雑さを追加:バックスラッシュ

代替リストのテキストを置き換えます。複雑さを追加:バックスラッシュ

1行に1つずつ文字列のペアを含むファイルAがあります。

\old1 \new1
\old2 \new2
.....

ファイルAを繰り返し、ファイルBの各行に対してグローバル置換(例: "\ old1 -> \ new1")を実行したいと思います。バックスラッシュなしで簡単に交換を完了するには、sedまたはperl -pi -eを使用してください。具体的な作業は次のとおりです。

while read -r line
do
 set -- $line
 sed -i -e s/$1/$2/g target
done < replacements

ただし、代替文字列でバックスラッシュを文字通り作成sedまたは処理する方法がわかりませんperl。きれいな解決策はありますか?

ベストアンサー1

[.*^$バックスラッシュだけでなく、区切り文字(sedの場合)を含む正規表現のすべての特殊文字をエスケープする必要がありますs。 Perlではこのquotemeta機能を使用してください。

試みのもう一つの問題は、set -- $lineシェルが実行されたときに自己拡張を実行することです。単語の分離に加えて、ワイルドカードも実行するため、行にa* b*名前があり、現在のディレクトリにファイルがある場合は置き換えます。と。このアプローチでは、ワイルドカードをオフにする必要があります。a1a2a1a2set -f

以下は、代替リストをsed引数リストに直接変更するソリューションです。ソースと代替テキストにスペース文字がないと仮定しますが、スペースと改行を除くすべての文字を正しく処理する必要があります。最初の置換は\保護する必要がある文字の前に追加され、2番目の置換は各行をからに変更しfoo bar ます-e s/foo/bar/g。警告、テストされていません。

set -f
sed_args=$(<replacement sed -e 's~[/.*[\\^$]~\\&~g' \
                            -e 's~^\([^ ]*\)  *\([^ ]*\).*~-e s/\1/\2/g~')
sed -i $sed_args target

Perlでは、Perlが代替ファイルを直接読み取るようにすると、参照関連の問題が軽減されます。繰り返しますが、テストされていません。

perl -i -pe 'BEGIN {
   open R, "<replacement" or die;
   while (<R>) {
       chomp;
       ($from, $to, @ignored) = split / +/;
       $s{$from} = $to;
   }
   close R;
   $regexp = join("|", map {quotemeta} keys %s);
}
s/($regexp)/$s{$1}/ego'

おすすめ記事