このsedコマンドが一番下の3番目の「and」を置き換えないのはなぜですか?

このsedコマンドが一番下の3番目の「and」を置き換えないのはなぜですか?

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\band.*\band\b

注文する

sed -E 's/(.*)\<and\>((.*\<and\>){2})/\1XYZ\2/'

sedOpenBSDでは、基本的に正しい操作を実行しているようです(使用\<\>交換)。\b

sed私はGNUまたはGNUの既存のバグレポートを見つけることができませんでしたglibc。少なくともそれでも驚かないでしょう。関連到着glibcエラー25322(なぜなら以下を参照してください)。

この問題をさらに詳しく解決できます。

sed -E 's/(.*)\band\b(.*\band\b.*\band\b)/\1XYZ\2/'

答え2

質問をすることをお勧めします。例をテストした結果GNU grepGNU 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
    

また、問題のある動作は、競合する単語の先頭に追加の文字がある場合にのみ発生します。たとえば、itsit。しかし、最後に文字がある場合はそうではありません。たとえば、itsiteitem

$ 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

関連情報