正则表达式匹配但捕获组仍然未初始化

时间:2014-06-17 15:29:42

标签: regex perl html-parsing

我是perl和regex的新手。我想我理解这个想法以及如何使用正则表达式,但我在编写脚本时遇到了问题。我有一些页面的内容,我正在尝试阅读一些信息。

my @rows = split(/<tr(\s)bgcolor=.{8}/,$content);

foreach my $row(@rows){
    if( $row =~/<td\s+nowrap\s+align=.*\s?(bgcolor=.*\s+)?>\w*\s?<\/td>/ig){
    print $1;
    print $file_opt $row."\n";

    # there will be more code later on
    } 
}

这给了我$1未初始化的错误。我明白当模式与字符串不匹配时会发生这种情况。但是我在if下有正则表达式 - 所以如果它进入if,它确实匹配,那么?如您所见,我将行打印到文件中。每一个都是这样的:

<td nowrap align="right">DOLNOŚLĄSKIE</td><td nowrap align="right" bgcolor=#D0E0D0 >0</td><td nowrap align="right">0</td><td nowrap align="right" bgcolor=#D0E0D0 >0</td><td nowrap align="right">0</td><td nowrap align="right" bgcolor=#D0E0D0 >0</td><td nowrap align="right">0</td><td nowrap align="right" bgcolor=#D0E0D0 >0</td><td nowrap align="right">0</td><td nowrap align="right" bgcolor=#D0E0D0 >0</td><td nowrap align="right">4</td><td nowrap align="right" bgcolor=#D0E0D0 >0</td><td nowrap align="right">1</td><td nowrap align="right" bgcolor=#D0E0D0 >1</td><td nowrap align="right">3</td><td nowrap align="right" bgcolor=#D0E0D0 >6</td><td nowrap align="right">1</td><td nowrap align="right" bgcolor=#D0E0D0 >2</td><td nowrap align="right">1</td><td nowrap align="right" bgcolor=#D0E0D0 >19</td><td nowrap align="right">0</td></tr>

来自$content的所有不必要的东西都不在文件中。那么这种模式是否匹配?

2 个答案:

答案 0 :(得分:4)

从帖子中的代码看,您似乎正在尝试捕获给定行中每个表格单元格的bgcolor属性。并非所有单元格都设置bgcolor,但其中一些单元格设置为use HTML::TreeBuilder 5 -weak; my $html = q{<td nowrap align="right">DOLNOŚLĄSKIE</td><td nowrap align="right" bgcolor=#D0E0D0 >0</td><td nowrap align="right">0</td><td nowrap align="right" bgcolor=#D0E0D0 >0</td><td nowrap align="right">0</td><td nowrap align="right" bgcolor=#D0E0D0 >0</td><td nowrap align="right">0</td><td nowrap align="right" bgcolor=#D0E0D0 >0</td><td nowrap align="right">0</td><td nowrap align="right" bgcolor=#D0E0D0 >0</td><td nowrap align="right">4</td><td nowrap align="right" bgcolor=#D0E0D0 >0</td><td nowrap align="right">1</td><td nowrap align="right" bgcolor=#D0E0D0 >1</td><td nowrap align="right">3</td><td nowrap align="right" bgcolor=#D0E0D0 >6</td><td nowrap align="right">1</td><td nowrap align="right" bgcolor=#D0E0D0 >2</td><td nowrap align="right">1</td><td nowrap align="right" bgcolor=#D0E0D0 >19</td><td nowrap align="right">0</td></tr>}; my $t = HTML::TreeBuilder->new_from_content($html); foreach my $col ( $t->look_down('_tag','tr')->content_list ) { print $col->attr('bgcolor'), "\n" if defined $col->attr('bgcolor'); } 。以下是使用HTML::TreeBuilder提取信息的方法:

use Mojo::DOM;

my $html = q{<td nowrap align="right">DOLNOŚLĄSKIE</td><td nowrap align="right" bgcolor=#D0E0D0 >0</td><td nowrap align="right">0</td><td nowrap align="right" bgcolor=#D0E0D0 >0</td><td nowrap align="right">0</td><td nowrap align="right" bgcolor=#D0E0D0 >0</td><td nowrap align="right">0</td><td nowrap align="right" bgcolor=#D0E0D0 >0</td><td nowrap align="right">0</td><td nowrap align="right" bgcolor=#D0E0D0 >0</td><td nowrap align="right">4</td><td nowrap align="right" bgcolor=#D0E0D0 >0</td><td nowrap align="right">1</td><td nowrap align="right" bgcolor=#D0E0D0 >1</td><td nowrap align="right">3</td><td nowrap align="right" bgcolor=#D0E0D0 >6</td><td nowrap align="right">1</td><td nowrap align="right" bgcolor=#D0E0D0 >2</td><td nowrap align="right">1</td><td nowrap align="right" bgcolor=#D0E0D0 >19</td><td nowrap align="right">0</td></tr>};

for my $td ( Mojo::DOM->new($html)->find('td[bgcolor]')->each ) {
  print $td->attr('bgcolor'), "\n";
}

我确定您需要检索的内容不止于此,但鉴于您的问题的含糊描述和不完整的代码,我们能够确定所有内容。

但重点是坚实的;不用正则表达式解析HTML,用HTML解析器解析HTML。它在开始时的学习曲线稍微陡峭,但结果将更加健壮,更易于维护,并且您学到的技能将适用于任何HTML文档,而不仅仅是这个特定的文档。

HTML :: TreeBuilder附带了一些很好的文档,但是您必须阅读其中很大一部分才能理解整个文档。

还有另一个HTML解析模块Mojo::Dom,它带有Mojolicious框架。就个人而言,我发现它更容易使用,但有时当我发布示例时,人们似乎得出结论,他们必须加载一些重量级的Web框架来使用它(这不是完全正确的,但我&#39我厌倦了游泳上游。;)。你可能想看看它,看看它是否更符合你的口味。这是一个例子:

#D0E0D0
#D0E0D0
#D0E0D0
#D0E0D0
#D0E0D0
#D0E0D0
#D0E0D0
#D0E0D0
#D0E0D0
#D0E0D0

这两个代码示例都将产生以下输出:

{{1}}

...这可能并不是非常有用,但正是您发布的代码似乎想要捕获的内容。至少它是一个起点,你应该能够适应自己的需要。

我相信Mojo :: DOM的文档更加平易近人,这可能会产生影响,特别是如果您是Perl的新手。我的建议是从那里开始,围绕该模块构建解决方案。在longrun中,使用正则表达式从HTML中提取数据比撕掉你的头发要好得多。

Mojolicious发行版在大多数系统上安装不到一分钟,包括Mojo :: DOM模块,它本身非常轻巧。这是一个不错的选择。

答案 1 :(得分:2)

不要手工制作正则表达式来解析html,yadda yadda,现在回答你的实际问题:

“但我在if下有正则表达式 - 所以如果它输入if,它确实匹配,对吧?”

在你的正则表达式中,你的捕获组后面有一个?量词。这意味着它可以(并且在您的示例中)匹配找到您的捕获组一次或不一次。如果正则表达式的最佳匹配恰好涉及捕获组零次,则不会捕获任何内容并且$1保持为空。摆脱那个问号,以确保你的正则表达式只有在实际捕获的东西时匹配。

如果在你的例子中使用它,它可以工作并捕获一些东西。

虽然人们可能会认为它总能捕获一些东西(如此处所示,当它突然在没有量词时工作)由于量词是贪婪的,那里有那么多的量词,它只是另一个首先变得贪婪。