2012-02-08 67 views
0

我遇到了另一个问题,涉及到一个网站,我想刮。Perl:为什么这个网页刮板正则表达式工作不一致?

基本上我已经剥离了我不想从页面内容中获得的大部分内容,也感谢here已经设法隔离我想要的日期。尽管一些初始问题与非破坏性空间相匹配,但大部分似乎工作正常。然而,我现在遇到了最后一个正则表达式的困难,这个正则表达式旨在将每行数据分割成字段。每条线代表股价指数的价格。在每一行中的字段是:

  1. 从字符从拉丁字母有时逗号或符号,没有NUMERICS制成任意长度的名称。
  2. 小数点后两位数字(索引的绝对值)的数字。
  3. 小数点后有两位数字的数字(值的变化)。
  4. 一个数字,小数点后有两位数字,后面跟着一个百分号(百分比变化的数值)。

下面是一个例子字符串,分裂前: “渔业,农业& Forestry243.45-1.91-0.78%Mining360.74-4.15-1.14%Construction465.36-1.01-0.22%Foods783.2511.281.46 %纺织品& Apparels412.070.540.13%的纸浆& Paper333.31-0.29-0.09%Chemicals729.406.010.83%“

我使用拆分此行的正则表达式是这样的:

$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% 

我认为减号是为这些索引一个问题,看到的价格产生负面变化索引,但有时它尽管减号仍然有效。

问:为什么下面显示的最终正则表达式不能一致地分割字段?

示例代码如下。

#!/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; 
+0

我假设数列开始他们之间的事情生活。但是当我们开始提取它们时,所有的数字都被卡在一起,只有(希望)固定格式来帮助我们取笑它们。如果您将分隔字符放入,会不会更容易? – zgpmax 2012-02-08 12:47:08

+0

公平的一点。这些数字最初是在5个不同的表中,所以它试图解析/保存每个表格或使用HTML :: Tree转储文本,并选择了后者。由于田地很规则,我不认为这会是一个问题,理论上我仍然认为这不应该成为一个问题。然而,在实践中,... – SlowLearner 2012-02-08 12:52:18

回答

2

它似乎在做每隔一个。

我的猜测是你的记录之间有一个单独的\n,但你的模式以\n开头和结尾。因此,第一场比赛的最后\n消耗\n,第二场比赛需要找到第二个记录。最终的结果是它能够记录所有其他记录。

你可能会更好的包裹图案^$(而不是\n\n),并使用m标志的s///

+0

谢谢,现在我看着它很令人生气。必须有一些“正则表达式的规律”,指出解决正则表达式问题的可能性与查看正则表达式的时间成反比。 – SlowLearner 2012-02-08 13:04:42

2

问题是,你有\n都在正则表达式的开始和结束。

考虑这样的事情:

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

,将设置$saxabaxaaxaxaxa,因为那里是aba只有两个不重叠的发生。

+0

谢谢,hochgurgler殴打你,但我赞赏你的榜样。 – SlowLearner 2012-02-08 13:06:30

0

我的解释(伪) -

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 parsing in perl参考MOJO 为基于DOM的解析perl,除非有严重的性能原因, 我强烈推荐这种方法。

+0

慢慢地得到正确的答案通常会比快速得到错误答案更好。 – 2012-02-09 20:28:39

相关问题