绕过模式匹配中的可选字段

  • 本文关键字:字段 模式匹配 perl
  • 更新时间 :
  • 英文 :


我试图提取球员的名字和总数,但在某些情况下,列表中球员的号码后面有一个额外的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 中提取,我会坚持使用多步骤。

  1. 清理
  2. 提取
  3. 更多清理

对于清理,我首先会检查什么是常见的。在这种情况下,每行都以<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>

最新更新