[英]Parsing a whole file in Perl
我有一个包含2列表的HTML文件,我想对其进行解析,以提取代表各列的字符串对。 HTML的页面布局(空白,换行)是任意的,因此我无法逐行解析文件。
我记得您可以通过将整个文件抓成一个字符串并在整个字符串上进行操作来解析这样的事情,我发现这更具挑战性。 我正在尝试以下操作:
#!/usr/bin/perl
open(FILE, "Glossary") || die "Couldn't open file\n";
@lines = <FILE>;
close(FILE);
$data = join(' ', @lines);
while ($data =~ /<tr>.*(<td>.*<\/td>).*(<td>.*<\/td>).*<\/tr>/g) {
print $1, ":", $2, "\n";
}
给出null
输出。 这是输入文件的一部分:
<table class="wikitable">
<tr>
<td><b>Term</b>
</td>
<td><b>Meaning</b>
</td></tr>
<tr>
<td><span id="0-Day">0-Day</span>
</td>
<td>
<p>See <a href="#Zero_Day">Zero Day</a>.
</p>
</td>
有人可以帮我吗?
CPAN中有一个HTML :: TableExtract模块,它可以简化您要解决的问题:
use strict;
use warnings;
use HTML::TableExtract qw(tree);
my $te = HTML::TableExtract->new( headers => qw(Term Meaning) );
my $html_file = "Glossary";
$te->parse_file($html_file);
my $table = $te->first_table_found;
# ...
您已经有了答案,可以解释为什么不应该使用正则表达式解析HTML。 而且你真的不应该。 但是您已经要求解释为什么您的代码不起作用。 所以这里...
您的代码中有两个问题。 一个停止它的工作,另一个停止它的工作,正如您所期望的。
首先,您正在使用.
在您的正则表达式中匹配任何字符。 但是.
与任何字符都不匹配。 它匹配除换行符以外的任何字符。 而且您的字符串中有换行符。 您可以通过在匹配运算符中添加/s
选项来解决此问题(因此它具有/gs
而不是/s
)。
有了该修复程序之后,您将从代码中得到结果。 使用您的测试数据,我看到:
<td><b>Term</b>
</td>:<td><b>Meaning</b>
</td>
哪个是对的。 但是查看您的测试数据,我想知道为什么我没有得到两个结果-因为/g
。 我很快意识到这是因为您的测试数据缺少结束</td>
。 当我添加它时,我得到了以下结果:
<td><span id="0-Day">0-Day</span>
</td>:<td>
<p>See <a href="#Zero_Day">Zero Day</a>.
</p>
</td>
好。 现在正在寻找第二个结果。 但是第一个发生了什么? 那是代码中的第二个错误。
您的正则表达式中有几次.*
。 那意味着“零个或多个字符”。 但是这里的问题是“或更多”。 默认情况下,Perl正则表达式限定符( *
或+
)是贪婪的。 这意味着他们将使用尽可能多的字符串。 正则表达式中的第一个.*
占用了大量字符串。 实际上所有这些都一直到第二个<tr>
。
解决方案是使.*
不贪心。 而您通过添加?
到最后。 因此,您可以将所有.*
替换为.*?
。 完成此操作后,我得到以下输出:
<td><b>Term</b>
</td>:<td><b>Meaning</b>
</td>
<td><span id="0-Day">0-Day</span>
</td>:<td>
<p>See <a href="#Zero_Day">Zero Day</a>.
</p>
</td>
这对我来说似乎是正确的。
因此,总结一下:
.
与换行符不匹配。 为此,您需要/s
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.