Используйте awk или sed для удаления всего между < >

Используйте awk или sed для удаления всего между < >

У меня в текстовом файле есть следующее:

<ol><li><b><a href="/page1/Mark_Yato" title="Mark Yato">Mark Yato</a> ft. MarkAm &amp; <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>

и пытаюсь сделать так, чтобы вывод был следующим:

Mark Yato ft. MarkAm & Givēon - Thuieo
The Central - AHTIOe oie
Taa Too A - ryhwtyw w

Чтобы добиться этого, я подумал, что попробую удалить символы «<», «>» и все, что между ними, чтобы остался только тот список, который я пытаюсь получить.

Я уже пробовал следующую команду sed:

sed 's/<[^()]*>//g'

но это выводит только следующее:

(7)
(7)
(8)

Что я делаю не так и как исправить команду sed или перевести ее в awk, если ее для этого лучше использовать?

решение1

Разбор разметки с помощью регулярных выраженийобщеизвестно проблематичный.

Хотя это и не является проблемой для вашего образца данных, угловые скобки могут появляться в атрибутах тегов, комментариях и, возможно, в других местах, делая регулярные выражения, соответствующие диапазону от <до, >ненадежными.

Вам следует прибегнуть к инструментам, реализующим парсер разметки.

Например, используяпандок(версия >= 2.8) с вашим образцом данных (без добавления отсутствующего </ol>тега):

$ 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)

Затем вы можете легко обработать этот вывод как обычный текст, удалив пустые строки и другие нежелательные части:

$ 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

Обратите внимание, что до версии 2.8 pandocиспользовался для преобразования любого выделенного текста в заглавные буквы при генерации выходных данных в plainформате. <b>Тег в элементах вашего списка будет вызывать это поведение (подробнее об этом вжурнал измененийили соответствующийсовершитьна GitHub).

В зависимости от фактических входных данных, обходным решением может быть использование формата входных данных as либо явно markdown:pandoc

pandoc -f markdown -t plain file

или неявно, учитывая, что это то, что pandocавтоматически принимается по умолчанию ( pandoc -t plain file).

решение2

Вы почти у цели — совпадения регулярных выражений «жадные», поэтому вам нужно сообщить шаблону, что закрывающий >символ не допускается внутри шаблона. Другими словами, [^()]*часть внутри шаблона будет соответствовать столько текста, сколько сможет «жадно». Если вы не скажете шаблону исключить закрытие >из этой части шаблона, то открытие <и закрытие >, которые использует Regex, не обязательно являются парными с точки зрения HTML.

Вместо этого используйте это:

sed -e 's/<[^>]*>//g'

Это заставляет регулярное выражение удалить каждый HTML-тег, а не большой блок текста, содержащий <и >на концах, а также <или >в середине.

решение3

Вы можете использовать phpдля удаления всех HTML-тегов и преобразования HTML-сущностей обратно в обычные символы:

$ <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)

Чтобы дополнительно удалить пробелы (пробелы, табуляции), за которыми следует открытие (, за которым следует одна или несколько цифр и закрытие )в конце строки 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

решение4

С использованием xmlstarlet:

xmlstarlet fo -H file |
xmlstarlet sel -E latin1 -t -v '//li' -nl 2>/dev/null |
xmlstarlet unesc | sed 's/ [^ ]*$//'

Это используется xmlstarletдля преобразования фрагмента HTML в правильно сформированный документ HTML (первая команда). Затем он извлекает значение каждого liузла (вторая команда). Наконец, он декодирует любые сущности HTML ( &amp;например). Последняя sedкоманда просто удаляет все после последнего пробела в каждой строке (в скобках есть числа, которые не должны быть частью вывода).

Вывод, полученный из документа, указанного в вопросе:

Mark Yato ft. MarkAm & Givēon - Thuieo
The Central - AHTIOe oie
Taa Too A - ryhwtyw w

Связанный контент