我正在尝试提取玩家的姓名和总数,但是在某些情况下,列表中的玩家编号后面还有一个额外的html标签。因此,当出现该字段时,我该如何绕过它。我不能在括号内加上括号,因为它将尝试匹配括号,对吗?
<tr><td>10<td>MANNY MACHADO - FA</td><td>37</td></tr>
<tr><td>107</td><td>ALEDMYS DIAZ - HOU</td><td>18</td></tr>
while($content =~ /<tr><td>\d+?\S+?<td>(.*?)\s-.*?<\/td><td>(\d+?)</g) {
my $player = $1;
my $total = $2;
print "\nPlayer => $player Total => $total\n";
}
我尝试使用“ \ S +?”绕过它,但是在这种情况下,它不会打印出播放器数量小于10的任何内容。
答案 0 :(得分:1)
对于HTML,XML等使用正则表达式通常是一个不好的想法。
相反,您应该使用适当的解析器将其转换为DOM,然后在DOM域中实现算法。以您的示例为例:
#!/usr/bin/perl
use warnings;
use strict;
use HTML::TreeBuilder;
my $parser = new HTML::TreeBuilder;
my $root = $parser->parse_file(\*DATA)
or die "HTML\n";
foreach my $row ($root->look_down(_tag => 'tr')) {
if (my @columns = $row->look_down(_tag => 'td')) {
my $player = $columns[1]->as_text();
my $total = $columns[2]->as_text();
print "Player => $player Total => $total\n";
}
}
exit 0;
__DATA__
<body>
<tr><td>10<td>MANNY MACHADO - FA</td><td>37</td></tr>
<tr><td>107</td><td>ALEDMYS DIAZ - HOU</td><td>18</td></tr>
</body>
试运行:
$ perl dummy.pl
Player => MANNY MACHADO - FA Total => 37
Player => ALEDMYS DIAZ - HOU Total => 18
答案 1 :(得分:1)
使用Mojo::DOM:
use strict;
use warnings;
use Mojo::DOM;
my $html = <<'EOD';
<tr><td>10<td>MANNY MACHADO - FA</td><td>37</td></tr>
<tr><td>107</td><td>ALEDMYS DIAZ - HOU</td><td>18</td></tr>
EOD
my $dom = Mojo::DOM->new($html);
foreach my $tr ($dom->find('tr')->each) {
my @cells = $tr->children('td')->each;
my $player = $cells[1]->all_text;
my $total = $cells[2]->all_text;
# or alternatively
my $player = $tr->at('td:nth-of-type(2)')->all_text;
my $total = $tr->at('td:nth-of-type(3)')->all_text;
print "\nPlayer => $player Total => $total\n";
}
答案 2 :(得分:0)
您需要匹配可选的</tr>
,因此可以在正则表达式中使用以下(?:<\/tr>)?
进行匹配。由于开头是?:
,因此这会导致一个非捕获组匹配0或1次。所以您的新正则表达式是
/<tr><td>\d+(?:<\/td>)?<td>(.*?)\s-.*?<\/td><td>(\d+?)</g
通常我会添加一些关于不使用正则表达式来解析HTML的信息,但是由于格式不正确的HTML,我会让它通过。但是,如果您可以控制创建HTML的内容,请尝试对其进行修复,以使<td>
和</td>
标签保持平衡。
答案 3 :(得分:0)
我也是一个愿意使用适当的HTML或XML模块来提取信息的人,就像上面已经说过的其他人一样。因此,我不会对此进行详细说明。
如果我必须从您显示的格式错误的html中提取内容,我会坚持采用多步骤的方法。
为进行清理,我将首先检查常见问题。在这种情况下,每行都以<tr>
开头,因此我愿意为此寻找行,在一些可选的空格之后跳过那些不是以<tr>
开头的行:
while (<>) {
next unless /^\s*<tr>/;
我注意到的下一个共同之处是,每个有趣的字段都以td
开头。因此,我将其替换为更简单的选项卡,例如选项卡。假设已经有选项卡,我首先将其替换为空格:
tr/\t/ /;
s/<td>/\t/g;
现在我拥有的是一些标签,这些标签散布在我真正需要的数据周围。我真正需要的数据前面有一个制表符。因此,让我们删除标签:
s/<.*?>//g;
最后我可以提取我的数据了:
my($dummy, $number, $player, $total)= split /\t/;
但是由于播放器中附加了一些内容(在-
之后),我们也将其删除
$player=~ s/\s-.*//;
print "\nPlayer => $player Total => $total\n";
}
将其放在一起并使用DATA:
while (<DATA>) {
next unless /^\s*<tr>/;
tr/\t/ /;
s/<td>/\t/g;
s/<.*?>//g;
my($dummy, $number, $player, $total)= split /\t/;
$player=~ s/\s-.*//;
print "\nPlayer => $player Total => $total\n";
}
__DATA__
<tr><td>10<td>MANNY MACHADO - FA</td><td>37</td></tr>
<tr><td>107</td><td>ALEDMYS DIAZ - HOU</td><td>18</td></tr>
请准备好您可能会遇到带有更多空白的数据,否则该方法将失败。
示例:
<tr>
<td>10
<td>MANNY MACHADO - FA</td>
<td>37</td>
</tr>
<tr><td>107</td>
<td>ALEDMYS DIAZ - HOU</td>
<td>18</td>
</tr>