У меня в текстовом файле есть следующее:
<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>
и пытаюсь сделать так, чтобы вывод был следующим:
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 ( &
например). Последняя sed
команда просто удаляет все после последнего пробела в каждой строке (в скобках есть числа, которые не должны быть частью вывода).
Вывод, полученный из документа, указанного в вопросе:
Mark Yato ft. MarkAm & Givēon - Thuieo
The Central - AHTIOe oie
Taa Too A - ryhwtyw w