我试图提取球员的名字和总数,但在某些情况下,列表中球员的号码后面有一个额外的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 => $totaln";
}
我尝试使用"\S+?"绕过它,但在这种情况下,它不会打印出玩家数量小于 10 的任何内容。
对HTML、XML 等使用正则表达式通常是一个坏主意。
相反,您应该使用适当的解析器将其转换为 DOM,然后在 DOM 域中实现您的算法。使用您的示例:
- 从文件或字符串解析 HTML
- (在文档中找到正确的表格 - 由于我没有完整的 HTML,因此在示例中省略了)
- 循环访问表中的行
- 从行的列中提取您要查找的信息
#!/usr/bin/perl
use warnings;
use strict;
use HTML::TreeBuilder;
my $parser = new HTML::TreeBuilder;
my $root = $parser->parse_file(*DATA)
or die "HTMLn";
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 => $totaln";
}
}
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
使用 Mojo::D OM:
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 => $totaln";
}
您需要匹配可选的</tr>
,因此您可以使用正则表达式中的以下(?:</tr>)?
来执行此操作。由于开始时的?:
,这使得非捕获组匹配 0 或 1 次。所以你的新正则表达式是
/<tr><td>d+(?:</td>)?<td>(.*?)s-.*?</td><td>(d+?)</g
通常我会添加一些关于不使用正则表达式来解析 HTML 的内容,但由于这不是格式良好的 HTML,我会让它通过。但是,如果您可以对创建HTML的内容进行一些控制,请尝试对其进行修复,以使<td>
和</td>
标记保持平衡。
我也是一个会选择适当的 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 => $totaln";
}
将其放在一起并使用数据:
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 => $totaln";
}
__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>