Perl: почему это регулярное выражение веб-скребок работает непоследовательно? - PullRequest
0 голосов
/ 08 февраля 2012

У меня возникла другая проблема, связанная с сайтом, который я пытаюсь очистить.

По сути, я удалил большую часть того, чего не хочу, из содержимого страницы, и благодаря некоторой помощи, предоставленной здесь удалось выделить даты, которые я хотел.Кажется, что большинство из них работает нормально, несмотря на некоторые начальные проблемы, связанные с неразрывным пробелом.Однако теперь у меня возникают трудности с последним регулярным выражением, которое предназначено для разбиения каждой строки данных на поля.Каждая строка представляет цену индекса цены акций.Поля в каждой строке:

  1. Имя произвольной длины, состоящее из символов латинского алфавита и иногда запятой или амперсанда, без цифр.
  2. Число с двумя цифрами последесятичная точка (абсолютное значение индекса).
  3. Число с двумя цифрами после десятичной точки (изменение значения).
  4. Число с двумя цифрами после десятичной точкис последующим знаком процента (процентное изменение значения).

Вот пример строки перед разделением: «Рыболовство, сельское и лесное хозяйство243.45-1.91-0.78% Добыча полезных ископаемых360.74-4.15-1,14% Строительство465,36-1,01-0,22% Продукты питания783.2511.281.46% Текстиль и одежда412.070.540.13% Целлюлоза и бумага333.31-0.29-0.09% Химические вещества729.406.010.83% "

Регулярное выражение IЯ использую, чтобы разделить эту строку это:

$mystr =~ s/\n(.*?)(\d{1,4}\.\d{2})(\-?\d{1,3}\.\d{2})(.*?%)\n/\n$1 == $2 == $3 == $4\n/ig;

Это работает иногда, но не в других случаях, и я не могу понять, почему это должно быть.(Удвоенные знаки равенства в приведенном ниже примере вывода используются для того, чтобы сделать разделение полей более заметным.)

Fishery, Agriculture & Forestry == 243.45 == -1.91 == -0.78%
Mining360.74-4.15-1.14%
Construction == 465.36 == -1.01 == -0.22%
Foods783.2511.281.46%

Я думал, что знак минус был проблемой для тех индексов, которые видели отрицательное изменение ценыиндекса, но иногда это работает, несмотря на знак минус.

Q.Почему последнее регулярное выражение, показанное ниже, не может последовательно разделить поля?

Ниже приведен пример кода.

#!/usr/bin/perl -w
use strict;
use LWP::Simple;
use HTML::Tree;

my $url_full = "http://www.tse.or.jp/english/market/STATISTICS/e06_past.html";

my $content = get($url_full);
# get dates:
(my @dates) = $content =~ /(?<=dateFormat\(')\d{4}\/\d{2}\/\d{2}(?='\))/g;
foreach my $date (@dates) { # convert to yyyy-mm-dd
    $date =~ s/\//-/ig;
}
my $tree = HTML::Tree->new();
$tree->parse($content);
my $mystr = $tree->as_text;

$mystr =~ s/\xA0//gi; # remove non-breaking spaces
# remove first chunk of text:
$mystr =~
  s/^(TSE.*?)IndustryIndexChange ?/IndustryIndexChange\n$dates[0]\n\n/gi;
$mystr =~ s/IndustryIndexChange ?/IndustryIndexChange/ig;
$mystr =~ s/IndustryIndexChange/Industry Index Change\n/ig;
$mystr =~ s/% /%\n/gi; # percent symbol is market for end of line
# indicate breaks between days:
$mystr =~ s/Stock.*?IndustryIndexChange/\nDAY DELIMITER\n/gi;
$mystr =~ s/Exemption from Liability.*$//g; # remove boilerplate at bottom

# and here's the problem regex...
# try to split it:
$mystr =~
  s/\n(.*?)(\d{1,4}\.\d{2})(\-?\d{1,3}\.\d{2})(.*?%)\n/\n$1 == $2 == $3 == $4\n/ig;

print $mystr;

Ответы [ 3 ]

2 голосов
/ 08 февраля 2012

Проблема в том, что у вас есть \n как в начале, так и в конце регулярного выражения.

Рассмотрим что-то вроде этого:

$s = 'abababa';
$s =~ s/aba/axa/g;

, который установит $s в axabaxa, , а не axaxaxa, потому что есть только два непересекающихся вхождения aba.

2 голосов
/ 08 февраля 2012

Похоже, что он делает все остальные.

Я предполагаю, что ваши записи имеют один \n между ними, но ваш паттерн начинается и заканчивается \n.Таким образом, последний \n в первом совпадении потребляет \n, который необходим второму совпадению для поиска второй записи.Конечным результатом является то, что он собирает все остальные записи.

Возможно, вам лучше обернуть ваш шаблон в ^ и $ (вместо \n и \n) и использовать m флаг на s///.

0 голосов
/ 08 февраля 2012

Моя интерпретация (псевдокод) -

one   = [a-zA-Z,& ]+
two   = \d{1,4}.\d\d
three = <<two>>
four  = <<two>>%

regex = (<<one>>)(<<two>>)(<<three>>)(<<four>>)
      = ([a-zA-Z,& ]+)(\d{1,4}.\d\d)(\d{1,4}.\d\d)(\d{1,4}.\d\d%)

Однако вы уже представлены «структурированными» данными в форме HTML. Почему бы не воспользоваться этим?

Разбор HTML в perl ссылки на MOJO для анализа на основе DOM в Perl, и если нет серьезных причин производительности, Я очень рекомендую такой подход.

...