Eu tenho o seguinte em um arquivo 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>
e estou tentando fazer com que a saída seja a seguinte:
Mark Yato ft. MarkAm & Givēon - Thuieo
The Central - AHTIOe oie
Taa Too A - ryhwtyw w
Para conseguir isso, pensei em tentar remover '<', '>' e tudo entre eles, para que fique apenas a lista que estou tentando obter.
Já tentei o seguinte comando sed:
sed 's/<[^()]*>//g'
mas isso está gerando apenas o seguinte:
(7)
(7)
(8)
O que estou fazendo de errado e como posso corrigir o comando sed ou traduzi-lo para awk se for melhor usá-lo para isso?
Responder1
Analisar marcação com expressões regulares énotoriamente problemático.
Embora não seja um problema com seus dados de amostra, colchetes angulares podem aparecer em atributos de tags, comentários e possivelmente em outros lugares, tornando expressões regulares que correspondem de <
a >
não confiáveis.
Você deve recorrer a ferramentas que implementem um analisador de marcação.
Por exemplo, usandopandoc(versão >= 2.8) com seus dados de amostra (sem adicionar a </ol>
tag ausente):
$ 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)
Você pode então facilmente pós-processar esta saída como texto normal para remover linhas vazias e outras partes indesejadas:
$ 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
Observe que, antes da versão 2.8, pandoc
era usado para converter qualquer texto enfatizado em letras maiúsculas ao gerar saída no plain
formato. A <b>
tag nos itens da sua lista acionaria esse comportamento (mais sobre isso noregistro de alteraçõesou o relevantecomprometer-seno GitHub).
Dependendo dos seus dados de entrada reais, uma solução alternativa poderia ser usar o formato de entrada markdown
as pandoc
', explicitamente:
pandoc -f markdown -t plain file
ou implicitamente, considerando que é o pandoc
padrão automático ( pandoc -t plain file
).
Responder2
Você está quase lá - as correspondências de regex são "gananciosos", então você precisa informar ao padrão que o >
caractere de fechamento não é permitido dentro do padrão. Dito de outra forma, a [^()]*
parte dentro do padrão corresponderá ao máximo de texto possível "avidamente". Se você não instruir o padrão a excluir o fechamento >
desta parte do padrão, a abertura <
e o fechamento >
que o Regex usa não serão necessariamente aqueles que estão emparelhados do ponto de vista HTML.
Use isto em vez disso:
sed -e 's/<[^>]*>//g'
Isso força a regex a excluir todas as tags HTML, e não um bloco maior de texto que possui <
e >
no final, bem como <
ou >
no meio.
Responder3
Você poderia usar php
para remover todas as tags HTML e converter as entidades HTML de volta aos caracteres normais:
$ <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 remover adicionalmente espaços em branco (espaços, tabulações) seguidos por uma abertura (
, seguida por um ou mais números e um fechamento )
nas linhas que terminam com 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
Responder4
Usando xmlstarlet
:
xmlstarlet fo -H file |
xmlstarlet sel -E latin1 -t -v '//li' -nl 2>/dev/null |
xmlstarlet unesc | sed 's/ [^ ]*$//'
Isto é usado xmlstarlet
para converter o fragmento HTML em um documento HTML bem formado (o primeiro comando). Em seguida, extrai o valor de cada li
nó (2º comando). Finalmente, ele decodifica qualquer entidade HTML ( &
por exemplo). O comando final sed
apenas exclui qualquer coisa após o último espaço em cada linha (há números entre parênteses que não deveriam fazer parte da saída).
A saída dada ao documento na pergunta:
Mark Yato ft. MarkAm & Givēon - Thuieo
The Central - AHTIOe oie
Taa Too A - ryhwtyw w