'abbc'という文字列があり、置き換えたいとします。
2回置き換えてみると、結果は望みどおりにはなりません。
echo 'abbc' | sed 's/ab/bc/g;s/bc/ab/g'
abab
では、以下のようにどのsedコマンドを置き換えることができますか?
echo abbc | sed SED_COMMAND
bcab
_ edit _ :実際には、テキストには2つ以上のパターンがある可能性があり、必要な置換数がわかりません。 sed
はストリームエディタであり、その置き換えは貪欲であるという回答があったので、そのためには何らかのスクリプト言語を使用する必要があると思います。
多分このようなもの:
sed 's/ab/~~/g; s/bc/ab/g; s/~~/bc/g'
~
を、文字列に含まれないことがわかっている文字に置き換えます。
次に、 oogaのanswer のバリエーションを示します。これは、値の再利用方法を確認することなく、複数の検索と置換のペアに対して機能します。
sed -i '
s/\bAB\b/________BC________/g
s/\bBC\b/________CD________/g
s/________//g
' path_to_your_files/*.txt
以下に例を示します。
前:
some text AB some more text "BC" and more text.
後:
some text BC some more text "CD" and more text.
\b
は単語の境界を示すことに注意してください。これは、________
が検索に干渉するのを防ぎます(UbuntuではGNU sed 4.2.2を使用しています)。 Wordの境界検索を使用していない場合、この手法は機能しない可能性があります。
また、これはs/________//g
を削除して&& sed -i 's/________//g' path_to_your_files/*.txt
をコマンドの最後に追加するのと同じ結果になりますが、パスを2回指定する必要はありません。
これの一般的なバリエーションは、\x0
の代わりに_\x0_
または________
を使用することです。ファイルにヌルが表示されないことがわかっている場合は、jthillとして 提案された 。
私はいつも "-e"で複数のステートメントを使う
$ sed -e 's:AND:\n&:g' -e 's:GROUP BY:\n&:g' -e 's:UNION:\n&:g' -e 's:FROM:\n&:g' file > readable.sql
これはすべてのAND、GROUP BY、UNION、FROMの前に '\ n'を追加します。 '&'は一致した文字列を意味し、 '\ n&'は一致した文字列を '\ n'で置き換えます。 '
sed
はストリームエディタです。欲張って検索して置き換えます。あなたが要求したことをする唯一の方法は、中間置換パターンを使用し、それを最後に戻すことです。
echo 'abcd' | sed -e 's/ab/xy/;s/cd/ab/;s/xy/cd/'
これはうまくいくかもしれません(GNU sed)。
sed -r '1{x;s/^/:abbc:bcab/;x};G;s/^/\n/;:a;/\n\n/{P;d};s/\n(ab|bc)(.*\n.*:(\1)([^:]*))/\4\n\2/;ta;s/\n(.)/\1\n/;ta' file
これは、保持スペース(HS)に準備されて保持され、その後各行に追加されるルックアップテーブルを使用します。一意のマーカー(この場合は\n
)が行の先頭に追加され、行の長さ全体に渡って検索を進めるための方法として使用されます。マーカーが行の終わりに達すると、プロセスは終了し、ルックアップテーブルに出力され、マーカーは破棄されます。
N.B.ルックアップテーブルは最初に作成され、置換文字列と衝突しないように2番目の一意のマーカー(この場合は:
)が選択されます。
いくつかのコメントで:
sed -r '
# initialize hold with :abbc:bcab
1 {
x
s/^/:abbc:bcab/
x
}
G # append hold to patt (after a \n)
s/^/\n/ # prepend a \n
:a
/\n\n/ {
P # print patt up to first \n
d # delete patt & start next cycle
}
s/\n(ab|bc)(.*\n.*:(\1)([^:]*))/\4\n\2/
ta # goto a if sub occurred
s/\n(.)/\1\n/ # move one char past the first \n
ta # goto a if sub occurred
'
テーブルは次のように機能します。
** ** replacement
:abbc:bcab
** ** pattern
Tclは 組み込み これを持っています
$ tclsh
% string map {ab bc bc ab} abbc
bcab
これは、現在位置から文字列を比較しながら、文字列を一度に1文字ずつ移動することで機能します。
Perlの場合:
Perl -E '
sub string_map {
my ($str, %map) = @_;
my $i = 0;
while ($i < length $str) {
KEYS:
for my $key (keys %map) {
if (substr($str, $i, length $key) eq $key) {
substr($str, $i, length $key) = $map{$key};
$i += length($map{$key}) - 1;
last KEYS;
}
}
$i++;
}
return $str;
}
say string_map("abbc", "ab"=>"bc", "bc"=>"ab");
'
bcab
これはoogasに基づいたawk
ですsed
echo 'abbc' | awk '{gsub(/ab/,"xy");gsub(/bc/,"ab");gsub(/xy/,"bc")}1'
bcab
以下のように試みることができる単一パターン発生のためのより簡単なアプローチであるかもしれません。 sedの/ ab/bc /; s/bc/ab/2 '
私の出力:
~# echo 'abbc' | sed 's/ab/bc/;s/bc/ab/2'
bcab
複数回出現する場合
sed 's/\(ab\)\(bc\)/\2\1/g'
例
~# cat try.txt
abbc abbc abbc
bcab abbc bcab
abbc abbc bcab
~# sed 's/\(ab\)\(bc\)/\2\1/g' try.txt
bcab bcab bcab
bcab bcab bcab
bcab bcab bcab
お役に立てれば !!