2020年5月26日更新
これがバグのようで、バグを報告しました。 IDは#41558です。
私はただ遊び心があり、sed
次の練習を思いついた。 「and」(サブストリングではなく単語)の最後から3番目の項目を置き換えて生成します。
dog XYZ foo and bar and baz land good
私はこれがうまくいくと思いました。
echo 'dog and foo and bar and baz land good' |
sed -E 's/(.*)\band\b((.*\band\b){2})/\1XYZ\2/'
しかし、実際には「and」の終わりに2番目の発生を置き換えます。私が考えることができる唯一の説明は、そのうちの1つに「土地」が含まれているということですが、「境界」という単語を\band\b
含めたので、そうすべきではないか?\b
答え1
sed
これは、PCREでサポートされているようにツアーなどがサポートされていないため、実行するのは難しいです。文字列を逆にして、最初から3番目に出てくる反転された単語を変えてから、もう一度置き換える方が簡単です。
$ echo 'dog and foo and bar and baz land good' | rev | sed 's/\<dna\>/XXX/3' | rev
dog XXX foo and bar and baz land good
表現がうまくいかない理由はバグのようです。逆参照は、以前の内容がまったく影響を与えていないかのように\3
文字列のようです。 baz land
\b
and
.*\band\b
注文する
sed -E 's/(.*)\<and\>((.*\<and\>){2})/\1XYZ\2/'
sed
OpenBSDでは、基本的に正しい操作を実行しているようです(使用\<
と\>
交換)。\b
sed
私はGNUまたはGNUの既存のバグレポートを見つけることができませんでしたglibc
。少なくともそれでも驚かないでしょう。関連到着glibcエラー25322(なぜなら以下を参照してください)。
この問題をさらに詳しく解決できます。
sed -E 's/(.*)\band\b(.*\band\b.*\band\b)/\1XYZ\2/'
答え2
質問をすることをお勧めします。例をテストした結果GNU grep
、GNU sed
同じ動作が発生しますGNU awk
。以下に記載されている1つのケースを除いて。
誤った出力:
$ echo 'cocoa' | sed -nE '/(\bco){2}/p' cocoa
sed -nE '/(\<co){2}/p'
また、awk '/(\<co){2}/'
誤動作がありますが、grep -E '(\<co){2}'
正しく出力が提供されません。動作が正確で出力がありません。
$ echo 'cocoa' | sed -nE '/\bco\bco/p'
it
出力エラー:完全な単語が1つだけ出てきます。with
$ echo 'it line with it here sit too' | sed -E 's/with(.*\bit\b){2}/XYZ/' it line XYZ too
動作が正確で、入力が変更されていません。
$ echo 'it line with it here sit too' | sed -E 's/with.*\bit\b.*\bit\b/XYZ/' it line with it here sit too
単語の境界を変更すると、
\<
他の\>
問題が発生します。これが正しい修正しないでください入力する:
$ echo 'it line with it here sit too' | sed -E 's/with(.*\<it\>){2}/XYZ/' it line with it here sit too
これは入力を正しく修正します。
$ echo 'it line with it here it too' | sed -E 's/with(.*\<it\>){2}/XYZ/' it line XYZ too
ただし、入力を変更することはできません。
$ echo 'it line with it here it too sit' | sed -E 's/with(.*\<it\>){2}/XYZ/' it line with it here it too sit
また、問題のある動作は、競合する単語の先頭に追加の文字がある場合にのみ発生します。たとえば、it
とsit
。しかし、最後に文字がある場合はそうではありません。たとえば、it
とsite
。item
$ echo 'it line with it here item too' | sed -E 's/with(.*\bit\b){2}/XYZ/'
it line with it here item too
$ echo 'it line with it here it too item' | sed -E 's/with(.*\<it\>){2}/XYZ/'
it line XYZ too item