perl - совпадение больше, чем характер в регулярном выражении - PullRequest
1 голос
/ 17 февраля 2020
$string1="<a href='/channels/folder1'>Alpha-Seeking";
$string2="<a href='/channels/folder2'>No Underlying Index ,";

Мне нужно извлечь "Alpha-Seeking" и "No Underlying Index" из 2 приведенных выше строк. По сути, нужно все от ('>) до последнего символа строки.

Пробовал двумя способами,

1) Стандартный интуитивно понятный

($string1=~ /\'>(.*?)/) {print "got $1";} 

, но это делает не похоже на работу с символом «>».

2) Также пробовал

if ($string1=~ /(?=>)(.*?)/) {print "got $1";} 

на основе входных данных из Больше и меньше символа в регулярных выражениях , но это не работает.

Любые входные данные будут полезны.

PS: Кроме того, если ответ может включать совпадение с символом "меньше чем" ("<"), это будет здорово! </p>

Спасибо

Ответы [ 4 ]

3 голосов
/ 17 февраля 2020

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

Например:

<tag>
  outer
  <tag>
    middle
    <tag>inner</tag>
    middle
  </tag>
  outer
</tag>

Вместо этого используйте синтаксический анализатор HTML и такие инструменты поиска, как XPath. .

Вот демонстрация с использованием XML :: Lib XML.

use strict;
use warnings;
use v5.10;

use XML::LibXML;

my $html = q{
<html>
<body>
    <a href='/channels/folder1'>Alpha-Seeking</a>
    <a href='/channels/folder2'>No Underlying Index</a>
</body>
</html>
};

# Parse the HTML
my $dom = XML::LibXML->load_html(string => $html);

# Find all links.
for my $node ($dom->findnodes('//a')) {
    # Print their text.
    say $node->textContent;
}
3 голосов
/ 17 февраля 2020

Я должен начать с повторения, что невероятно неразумно разбирать HTML или XML с регулярными выражениями. Пожалуйста, рассмотрите возможность использования правильного HTML парсера.

Сказав это, ваша проблема здесь довольно легко исправить. То, что вы называете «стандартным интуитивным подходом», прекрасно работает с простой настройкой.

Вот что у вас есть:

if ($string1=~ /\'>(.*?)/) {print "got $1";} 

И ваше регулярное выражение \'>(.*?). Это означает «найти буквальную кавычку, за которой следует знак« больше, чем », а затем зафиксировать минимальное количество всего, что следует за этим» Проблема в «минимальной сумме». Самая простая вещь, которую .*? может захватить, это ничто - пустая строка.

Регулярные выражения по умолчанию жадные; они соответствуют как можно больше. Вы добавляете ?, чтобы убрать эту жадность и заставить их совпадать как можно меньше. Но ты не хочешь этого здесь. Здесь вы хотите их жадность. Так что просто удалите это ?.

use warnings;
use strict;

my @strings = (
 "<a href='/channels/folder1'>Alpha-Seeking",
 "<a href='/channels/folder2'>No Underlying Index ,"
);

for my $string (@strings) {
  if ($string =~ /'>(.*)/) { # Note: No "?" here
    print "got $1\n";
  }
}

Это отобразит:

got Alpha-Seeking
got No Underlying Index ,
2 голосов
/ 17 февраля 2020

Это работает для меня

use warnings;
use strict;

my @strings = (
 "<a href='/channels/folder1'>Alpha-Seeking",
 "<a href='/channels/folder2'>No Underlying Index ,"
);

for my $string (@strings)
{
    if ($string =~ /'>(.*?)$/) 
    {
        print "got $1\n";
    } 
} 

работает, это дает

$ perl /tmp/abc.pl
got Alpha-Seeking
got No Underlying Index ,
0 голосов
/ 18 февраля 2020

При изучении различных опций мне удалось заставить это работать со следующим:

Заменить знак больше чем на какой-либо другой универсальный символ c (например, трубу)

$string=~ s/>/\|/g;                 #Interestingly, '>' matches here without any issues

После этого разделите на символ трубы и напечатайте / проанализируйте вторую часть:

    ($o1,$o2) = split(/\|/, $string);
    print "$o2|";

Прекрасно работает как обходной путь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...