У меня есть файл, который выглядит примерно так:
<table name="content_analyzer" primary-key="id">
<type="global" />
</table>
<table name="content_analyzer2" primary-key="id">
<type="global" />
</table>
<table name="content_analyzer_items" primary-key="id">
<type="global" />
</table>
Мне нужно извлечь что-нибудь в следующих кавычках name=
, то есть content_analyzer
, content_analyzer2
и content_analyzer_items
.
Я делаю это в системе Linux, поэтому решение с использованием sed, perl, grep или bash подойдет.
regex
perl
sed
html-parsing
text-extraction
спорщик
источник
источник
Ответы:
Поскольку вам нужно сопоставить контент, не включая его в результат (должен совпадать,
name="
но не является частью желаемого результата), требуется некоторая форма сопоставления нулевой ширины или группового захвата. Это легко сделать с помощью следующих инструментов:Perl
С Perl вы можете использовать
n
опцию для цикла построчно и распечатать содержимое группы захвата, если оно совпадает:perl -ne 'print "$1\n" if /name="(.*?)"/' filename
GNU grep
Если у вас есть улучшенная версия grep, такая как GNU grep, у вас может быть
-P
доступная опция. Эта опция включит регулярное выражение, подобное Perl, что позволит вам использовать\K
сокращенный просмотр назад. Он сбросит положение совпадения, поэтому все, что до него, будет нулевой шириной.grep -Po 'name="\K.*?(?=")' filename
Эта
o
опция заставляет grep печатать только совпавший текст, а не всю строку.Vim - текстовый редактор
Другой способ - напрямую использовать текстовый редактор. В Vim одним из различных способов добиться этого было бы удаление строк без
name=
и последующее извлечение содержимого из полученных строк::v/.*name="\v([^"]+).*/d|%s//\1
Стандартный grep
Если по какой-то причине у вас нет доступа к этим инструментам, нечто подобное можно сделать с помощью стандартного grep. Однако без осмотра позже потребуется некоторая очистка:
grep -o 'name="[^"]*"' filename
Примечание о сохранении результатов
Результаты всех вышеперечисленных команд будут отправлены по адресу
stdout
. Важно помнить, что вы всегда можете сохранить их, подключив его к файлу, добавив:до конца команды.
источник
grep
):grep -Po '.*name="\K.*?(?=".*)'
.*
стороне, надеюсь, вы не рассердитесь на меня. Я хотел бы спросить, видите ли вы какую-либо пользу от не жадного совпадения перед «чем угодно, кроме"
»? Не воспринимайте это как борьбу, мне просто любопытно, и я не эксперт по регулярным выражениям. Кроме того,\K
чаевые, действительно хорошие. Спасибо, Деннис..*
можно обойтисьgrep -Po '(?<=name=").*?(?=")'
.\K
Может быть использован для стенографии, но это действительно необходимо только , если матч с его левым переменной длиной. В подобных случаях причина использования поиска довольно очевидна. Неладные операции выглядят немного аккуратнее ([^"]*
вместо.*?
того, чтобы повторять характер привязки. Я не знаю о скорости. Думаю, это во многом зависит от контекста. Надеюсь, это поможет.\K
(после исследования) и удалил его,.*
была та же: сделать его красивее (проще). И я никогда не думал использовать.*?
вместо "традиционный способ", которому я где-то научился. Но «нежадный» здесь действительно имеет смысл. Спасибо, Деннис, наилучшие пожелания.Регулярное выражение будет таким:
.+name="([^"]+)"
Тогда группировка будет в \ 1
источник
Если вы используете Perl, загрузите модуль для анализа XML: XML :: Simple , XML :: Twig или XML :: LibXML . Не изобретайте колесо заново.
источник
<type="global"
например), поэтому большинство анализаторов XML просто жалуются и умирают.Для этой цели следует использовать парсер HTML, а не регулярные выражения. Программа на Perl, которая использует
HTML::TreeBuilder
:Программа
#!/usr/bin/env perl use strict; use warnings; use HTML::TreeBuilder; my $tree = HTML::TreeBuilder->new_from_file( \*DATA ); my @elements = $tree->look_down( sub { defined $_[0]->attr('name') } ); for (@elements) { print $_->attr('name'), "\n"; } __DATA__ <table name="content_analyzer" primary-key="id"> <type="global" /> </table> <table name="content_analyzer2" primary-key="id"> <type="global" /> </table> <table name="content_analyzer_items" primary-key="id"> <type="global" /> </table>
Вывод
источник
это могло сделать это:
perl -ne 'if(m/name="(.*?)"/){ print $1 . "\n"; }'
источник
Вот решение с использованием HTML tidy и xmlstarlet:
htmlstr=' <table name="content_analyzer" primary-key="id"> <type="global" /> </table> <table name="content_analyzer2" primary-key="id"> <type="global" /> </table> <table name="content_analyzer_items" primary-key="id"> <type="global" /> </table> ' echo "$htmlstr" | tidy -q -c -wrap 0 -numeric -asxml -utf8 --merge-divs yes --merge-spans yes 2>/dev/null | sed '/type="global"/d' | xmlstarlet sel -N x="http://www.w3.org/1999/xhtml" -T -t -m "//x:table" -v '@name' -n
источник
Ой, конечно, команда sed должна предшествовать команде tidy:
echo "$htmlstr" | sed '/type="global"/d' | tidy -q -c -wrap 0 -numeric -asxml -utf8 --merge-divs yes --merge-spans yes 2>/dev/null | xmlstarlet sel -N x="http://www.w3.org/1999/xhtml" -T -t -m "//x:table" -v '@name' -n
источник
Если структура вашего xml (или текста в целом) исправлена, самый простой способ - использовать
cut
. Для вашего конкретного случая:echo '<table name="content_analyzer" primary-key="id"> <type="global" /> </table> <table name="content_analyzer2" primary-key="id"> <type="global" /> </table> <table name="content_analyzer_items" primary-key="id"> <type="global" /> </table>' | grep name= | cut -f2 -d '"'
источник