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 sed
y 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 \b
palabra límites.
Respuesta1
Esto es difícil de hacer ya que sed
no 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 \3
parece ser la cadena baz land
, como si el \b
antes and
nunca .*\band\b
hubiera 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 sed
o GNU glibc
sobre 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 grep
y . Excepto un caso, que se detalla a continuación.GNU sed
GNU awk
Salida incorrecta:
$ echo 'cocoa' | sed -nE '/(\bco){2}/p' cocoa
sed -nE '/(\<co){2}/p'
yawk '/(\<co){2}/'
también tiene el comportamiento de error, perogrep -E '(\<co){2}'
no da resultados correctamenteComportamiento correcto, sin salida:
$ echo 'cocoa' | sed -nE '/\bco\bco/p'
Salida incorrecta: solo hay 1 palabra completa
it
despué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, it
y sit
. Pero no si hay personajes al final. Por ejemplo, it
y site
y 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