¿Por qué este comando sed no reemplaza el penúltimo "y"?

¿Por qué este comando sed no reemplaza el penúltimo "y"?

Actualización 26/05/2020

Parecía que se trataba de un error, así que presenté un error. Su identificación es #41558.


Estaba jugando sedy se me ocurrió este ejercicio: reemplazar la antepenúltima aparición de "y" (la palabra, no como una subcadena), para crear:

dog XYZ foo and bar and baz land good

Pensé que esto funcionaría

echo 'dog and foo and bar and baz land good' |
    sed -E 's/(.*)\band\b((.*\band\b){2})/\1XYZ\2/'

pero en realidad reemplaza la penúltima aparición de "y". La única explicación que se me ocurre es que incluye "tierra" como uno de los \band\b, pero ese no debería ser el caso porque incluí la \bpalabra límites.

Respuesta1

Esto es difícil de hacer ya que sedno admite búsquedas, etc. (como se puede hacer en un PCRE). Sería más fácil invertir la cadena y reemplazar la tercera aparición de la palabra invertida desde el principio, y luego invertirla nuevamente.

$ 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

En cuanto a por qué su expresión no funciona, parece un error. La referencia inversa \3parece ser la cadena  baz land, como si el \bantes andnunca .*\band\bhubiera tenido ningún efecto.

El comando

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

parece hacer lo correcto en OpenBSD con su nativo sed(que usa \<y \>en lugar de \b).

Todavía tengo que encontrar un informe de error existente contra GNU sedo GNU glibcsobre esto, aunque no me sorprendería si al menos fuerarelacionadoaerror glibc 25322(porque, ver más abajo).

Puedes solucionarlo siendo un poco más detallado:

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

Respuesta2

Sugeriría presentar un problema. He probado estos ejemplos, lo que da como resultado el mismo comportamiento con GNU grepy . Excepto un caso, que se detalla a continuación.GNU sedGNU awk

  • Salida incorrecta:

    $ echo 'cocoa' | sed -nE '/(\bco){2}/p'
    cocoa
    

    sed -nE '/(\<co){2}/p'y awk '/(\<co){2}/'también tiene el comportamiento de error, pero grep -E '(\<co){2}'no da resultados correctamente

  • Comportamiento correcto, sin salida:

    $ echo 'cocoa' | sed -nE '/\bco\bco/p'
    
  • Salida incorrecta: solo hay 1 palabra completa itdespuéswith

    $ echo 'it line with it here sit too' | sed -E 's/with(.*\bit\b){2}/XYZ/'
    it line XYZ too
    
  • Comportamiento correcto, la entrada no se modifica.

    $ echo 'it line with it here sit too' | sed -E 's/with.*\bit\b.*\bit\b/XYZ/'
    it line with it here sit too
    
  • Cambiar los límites de las palabras da \<como \>resultado un problema diferente.

    esto correctamenteno modificala entrada:

    $ echo 'it line with it here sit too' | sed -E 's/with(.*\<it\>){2}/XYZ/'
    it line with it here sit too
    

    Esto modifica correctamente la entrada.

    $ echo 'it line with it here it too' | sed -E 's/with(.*\<it\>){2}/XYZ/'
    it line XYZ too
    

    Pero este no logra modificar la entrada.

    $ echo 'it line with it here it too sit' | sed -E 's/with(.*\<it\>){2}/XYZ/'
    it line with it here it too sit
    

Además, el comportamiento problemático se observa sólo si la palabra en conflicto tiene caracteres adicionales al principio. Por ejemplo, ity sit. Pero no si hay personajes al final. Por ejemplo, ity sitey 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

información relacionada