Tengo un archivo con varias cadenas que provienen de un texto con formato HTML, por lo que tienen algunas secuencias HTML que no se ven bien en una interfaz de consola. He aquí un ejemplo:
Text1™
[Text®2]
Text:3
Lo que estoy intentando es eliminar todo lo que esté entre & y ; para que el texto sea legible nuevamente, como el siguiente:
Text1
Text2
Text3
De hecho, estoy intentando usar sed para eliminar los caracteres adicionales:
sed 's#&*;##g' <file>
El problema es que solo elimina el ; de las cadenas de texto.
La pregunta entonces es, ¿cómo se debe codificar la expresión regex para eliminar la cadena adicional?&#[1-9]+;
Respuesta1
Tu expresión regular
sed 's#&*;##g' <file>
no hace lo que crees que hace. El *
carácter es un multiplicador que dice que el carácter anterior se repite 0 o más veces. El carácter anterior es &
, por lo que coincidiría, por ejemplo, &&&;
con ;
( &
¡se escribe 0 veces antes ;
! Esto es lo que coincide en sus casos de prueba), pero no con lo que desea en este caso.
Necesitas especificar "cualquiercarácter" antes del multiplicador, que está representado por un solo punto, .
.
$ echo 'Text:3' | sed 's#&.*;##g'
Text3
Ese fue el primer problema. El segundo es el concepto de la llamada coincidencia "codiciosa": sed
verá la primera &
y luego intentará hacer coincidir la cadena más grande que pueda. Si tienes varias entidades HTML en una sola línea, esto sería un problema ya que:
$ echo 'Text:3 and some more text å and end' | sed 's#&.*;##g'
Text and end
Si desea ver una solución en el sed
contexto, puede buscar el carácter final de la entidad haciendo coincidir cualquier número de "no ;
" antes de un cierre ;
haciendo:
$ echo 'Text:3 and some more text å and end' | sed 's#&[^;]*;##g'
Text3 and some more text and end
Aún tendrás problemas con los usos legítimos del signo comercial ( &
) en el texto (bueno, &
es el uso "legítimo" real, pero el mundo real no siempre es tan analizable como el ideal) y con demasiadas coincidencias, pero esto explica ¿Por qué sed
se comporta como lo hace?
Respuesta2
¿No es mejor sustituir los códigos por los caracteres reales?
echo 'Text1™
[Text®2]
Text:3' | perl -C -pe 's/&#([^;]*)/chr$1/eg'
Producción:
Text1™;
[;Text®;2];
Text:;3