Tengo lo siguiente en un archivo txt:
<ol><li><b><a href="/page1/Mark_Yato" title="Mark Yato">Mark Yato</a> ft. MarkAm & <a href="/page1/Giv%C4%93on" title="Givēon">Givēon</a> - <a href="/page1/Mark_Yato:Thuieo" title="Mark Yato:Thuieo">Thuieo</a> (7)</b></li>
<li><b><a href="/page1/The_Central" title="The Central">The Central</a> - <a href="/page1/The_Central:AHTIOe oie" title="The Central:AHTIOe oie">AHTIOe oie</a> (7)</b></li>
<li><b><a href="/page1/Taa_Too_A" title="Taa Too A">Taa Too A</a> - <a href="/page1/Taa_Too_A:ryhwtyw w" title="Taa Too A:ryhwtyw w">ryhwtyw w</a> (8)</b></li>
y estoy tratando de que el resultado sea el siguiente:
Mark Yato ft. MarkAm & Givēon - Thuieo
The Central - AHTIOe oie
Taa Too A - ryhwtyw w
Para lograr esto, pensé en intentar eliminar '<', '>' y todo lo que hay entre ellos para que quede solo la lista que estoy tratando de obtener.
Ya probé el siguiente comando sed:
sed 's/<[^()]*>//g'
pero esto genera solo lo siguiente:
(7)
(7)
(8)
¿Qué estoy haciendo mal y cómo puedo arreglar el comando sed o traducirlo a awk si es mejor usarlo para eso?
Respuesta1
Analizar el marcado con expresiones regulares esnotoriamente problemático.
Si bien no es un problema con los datos de muestra, los corchetes angulares pueden aparecer en atributos de etiquetas, comentarios y posiblemente en otros lugares, lo que hace que las expresiones regulares que coinciden con no <
sean >
confiables.
Deberías recurrir a herramientas que implementen un analizador de marcado.
Por ejemplo, usandopandoc(versión >= 2.8) con sus datos de muestra (sin agregar la </ol>
etiqueta que falta):
$ pandoc -f html -t plain file
Mark Yato ft. MarkAm & Givēon - Thuieo (7)
The Central - AHTIOe oie (7)
Taa Too A - ryhwtyw w (8)
Luego podrás postprocesar fácilmente este resultado como texto normal para eliminar líneas vacías y otras partes no deseadas:
$ pandoc -f html -t plain file |
sed -e '/^$/d' -e 's/[[:blank:]]*([[:digit:]]*)$//'
Mark Yato ft. MarkAm & Givēon - Thuieo
The Central - AHTIOe oie
Taa Too A - ryhwtyw w
Tenga en cuenta que, antes de la versión 2.8, pandoc
se utilizaba para convertir cualquier texto resaltado a mayúsculas al generar resultados en plain
formato. La <b>
etiqueta en los elementos de su lista desencadenaría este comportamiento (más sobre esto en elregistro de cambioso el relevantecomprometerseen GitHub).
Dependiendo de sus datos de entrada reales, una solución alternativa podría ser utilizar el formato de entrada markdown
as pandoc
, ya sea explícitamente:
pandoc -f markdown -t plain file
o implícitamente, considerando que es lo que pandoc
automáticamente toma por defecto ( pandoc -t plain file
).
Respuesta2
Ya casi has llegado: las coincidencias de expresiones regulares son "codiciosas", por lo que debes decirle al patrón que el >
carácter de cierre no está permitido dentro del patrón. Dicho de otra manera, la [^()]*
parte dentro del patrón coincidirá con la mayor cantidad de texto posible "con avidez". Si no le dice al patrón que excluya el cierre >
de esta parte del patrón, la apertura <
y el cierre >
que usa Regex no son necesariamente los que están emparejados desde un punto de vista HTML.
Utilice esto en su lugar:
sed -e 's/<[^>]*>//g'
Esto obliga a la expresión regular a eliminar cada etiqueta HTML, no un bloque de texto más grande que tenga <
y >
en los extremos, así como <
o >
en el medio.
Respuesta3
Puede utilizar php
para eliminar todas las etiquetas HTML y convertir las entidades HTML a caracteres normales:
$ <file php -r 'echo htmlspecialchars_decode(strip_tags(file_get_contents("php://stdin")), ENT_HTML5);'
Mark Yato ft. MarkAm & Givēon - Thuieo (7)
The Central - AHTIOe oie (7)
Taa Too A - ryhwtyw w (8)
Para eliminar adicionalmente espacios en blanco (espacios, tabulaciones) seguidos de una apertura (
, seguido de uno o más números y un cierre )
en la línea que termina en sed
:
$ <file php -r 'echo htmlspecialchars_decode(strip_tags(file_get_contents("php://stdin")), ENT_HTML5);' |
sed 's/[[:blank:]]*([[:digit:]][[:digit:]]*)$//'
Mark Yato ft. MarkAm & Givēon - Thuieo
The Central - AHTIOe oie
Taa Too A - ryhwtyw w
Respuesta4
Usando xmlstarlet
:
xmlstarlet fo -H file |
xmlstarlet sel -E latin1 -t -v '//li' -nl 2>/dev/null |
xmlstarlet unesc | sed 's/ [^ ]*$//'
Esto se utiliza xmlstarlet
para convertir el fragmento HTML en un documento HTML bien formado (el primer comando). Luego extrae el valor de cada li
nodo (el segundo comando). Finalmente, decodifica cualquier entidad HTML ( &
por ejemplo). El sed
comando final simplemente elimina todo lo que hay después del último espacio en cada línea (hay números entre paréntesis que no deberían formar parte del resultado).
El resultado dado el documento en la pregunta:
Mark Yato ft. MarkAm & Givēon - Thuieo
The Central - AHTIOe oie
Taa Too A - ryhwtyw w