Вопрос

У меня есть HTML-файл, и я хотел бы извлечь текст между <li> и </li> теги.Конечно, существует миллион способов сделать это, но я решил, что было бы полезно привыкнуть делать это с помощью простых команд оболочки:

awk '/<li[^>]+><a[^>]+>([^>]+)<\/a>/m' cities.html

Проблема в том, что это печатает все тогда как я просто хочу напечатать совпадение в скобках - ([^>]+) -- либо awk это не поддерживает, либо я некомпетентен.Последнее кажется более вероятным.Если бы вы хотели применить предоставленное регулярное выражение к файлу и извлечь только указанные совпадения, как бы вы это сделали?Я уже знаю полдюжины других способов, но мне не хочется позволять awk выиграй этот раунд ;)

Редактировать:Данные не очень хорошо структурированы, поэтому использование позиционных совпадений ($1, $2, etc.) недопустимо.

Это было полезно?

Решение

По вашему сценарию, если вы сможете получить то, что хотите (это значит <li> и <a> тег находится в одной строке.);

$ cat test.html | awk 'sub(/<li[^>]*><a[^>]*>/,"")&&sub(/<\/a>.*/,"")'

или

$ cat test.html | gawk '/<li[^>]*><a[^>]*>(.*?)<\/a>.*/&&$0=gensub(/<li[^>]*><a[^>]*>(.*?)<\/a>.*/,"\\1", 1)'

Первый — для всех awk, второй — для gnu awk.

Другие советы

Если вы хотите сделать это в общем случае, когда теги вашего списка могут содержать любую допустимую HTML-разметку, тогда awk это неправильный инструмент.Подходящим инструментом для этой работы будет анализатор HTML, которому вы можете доверять, чтобы исправить все мелкие детали анализа HTML, включая варианты HTML и искаженный HTML.

Если вы делаете это для особого случая, когда вы можете управлять форматированием HTML, вы можете сделать awk работать для вас.Например, предположим, что вы можете гарантировать, что каждый элемент списка никогда не занимает более одной строки и всегда заканчивается символом </li> в одной строке, никогда не содержит никакой разметки (например, список, содержащий список), то вы можете использовать awk для этого, но нужно написать целое awk программа, которая сначала находит строки, содержащие элементы списка, а затем использует другие awk команды, чтобы найти только интересующую вас подстроку.

А вообще, awk это неправильный инструмент для этой работы.

gawk -F'<li>' -v RS='</li>' 'RT{print $NF}' file

У меня сработало очень хорошо.

Я вижу несколько проблем:

  • В конце шаблона стоит буква «m», которая важна для многострочных совпадений в Perl, но Awk не использует регулярные выражения, совместимые с Perl.(По крайней мере, стандартный (не GNU) awk этого не делает.)
  • Игнорируя это, кажется, что шаблон ищет «элемент стартового списка», за которым следует привязка «<a>' к '</a>', а не конечный элемент списка.
  • Вы ищете все, что не '>' как тело якоря;это не является автоматически неправильным, но, возможно, было бы более привычно искать что-то, что не является '<', или что-нибудь, что не является ни тем, ни другим.
  • Awk не выполняет многострочный поиск.
  • В Авке '$1' обозначает первое поле, где поля разделены символами-разделителями полей, которые по умолчанию являются пробелами.
  • В классическом nawk (как описано в 'sed & awk'книга выпуска 1991 года) не имеет механизма для извлечения подполей из совпадений и т. д.

Неясно, подойдет ли Awk для этой работы.Действительно, не совсем ясно, являются ли регулярные выражения подходящим инструментом для этой работы.

Я действительно не знаю awk, а как насчет Perl?

tr -d '\012' the.html | perl \
-e '$text = <>;' -e 'while ( length( $text) > 0)' \
-e '{ $text =~ /<li>(.*?)<\/li>(.*)/; $target = $1; $text = $2; print "$target\n" }'

1) удалить символы новой строки из файла, передать через Perl

2) инициализировать переменную полным текстом, запустить цикл, пока текст не исчезнет

3) выполнить «нежадное» сопоставление для материалов, ограниченных тегами элементов списка, сохранить и распечатать цель, подготовиться к следующему проходу

Имеет смысл?(предупреждение, сам не пробовал этот код, скоро нужно идти домой...)

P.S.— «perl -n» — это режим Awk (nawk?).Perl во многом является расширенной версией Awk, поэтому я никогда не удосужился изучить Awk.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top