我有一堆HTML文件,我想要做的是在每个HTML文件中查找关键字'From Argumbay'并使用我拥有的一些href来更改它。 起初我觉得它非常简单,所以我做的是打开每个HTML文件并将其内容加载到数组(列表)中,然后我查找每个关键字并将其替换为s ///,并将内容转储到文件,有什么问题?有时关键字也可以出现在href中,在这种情况下我不希望它被替换,或者它可以出现在某些标签内等等。
示例:http://www.astrosociety.org/education/surf.html
我希望我的脚本用$ href中的一些href替换'here'这个词的每个出现,但正如你所看到的,还有另一个'here'已经被href'ed,我不想要再来一次这个。 在这种情况下除了href之外没有其他'这里有',但我们假设有。
我想只更换关键字,如果它只是文字,任何想法?
BOUUNTY编辑:嗨,我相信它很简单,但似乎它删除了HTML,SHTML文件中发现的所有注释(主要问题是它在SHTML中删除了SSI),我尝试使用:store_comments(1 )在调用递归函数之前对$ html的方法,但无济于事。知道我在这里缺少什么吗?
答案 0 :(得分:7)
要使用HTML::TreeBuilder执行此操作,您将读取文件,修改树并将其写出(到同一文件或其他文件)。这相当复杂,因为您尝试将文本节点的一部分转换为标记,并且因为您有无法移动的注释。
HTML-Tree的一个常见习惯是使用修改树的递归函数:
use strict;
use warnings;
use 5.008;
use File::Slurp 'read_file';
use HTML::TreeBuilder;
sub replace_keyword
{
my $elt = shift;
return if $elt->is_empty;
$elt->normalize_content; # Make sure text is contiguous
my $content = $elt->content_array_ref;
for (my $i = 0; $i < @$content; ++$i) {
if (ref $content->[$i]) {
# It's a child element, process it recursively:
replace_keyword($content->[$i])
unless $content->[$i]->tag eq 'a'; # Don't descend into <a>
} else {
# It's text:
if ($content->[$i] =~ /here/) { # your keyword or regexp here
$elt->splice_content(
$i, 1, # Replace this text element with...
substr($content->[$i], 0, $-[0]), # the pre-match text
# A hyperlink with the keyword itself:
[ a => { href => 'http://example.com' },
substr($content->[$i], $-[0], $+[0] - $-[0]) ],
substr($content->[$i], $+[0]) # the post-match text
);
} # end if text contains keyword
} # end else text
} # end for $i in content index
} # end replace_keyword
my $content = read_file('foo.shtml');
# Wrap the SHTML fragment so the comments don't move:
my $html = HTML::TreeBuilder->new;
$html->store_comments(1);
$html->parse("<html><body>$content</body></html>");
my $body = $html->look_down(qw(_tag body));
replace_keyword($body);
# Now strip the wrapper to get the SHTML fragment back:
$content = $body->as_HTML;
$content =~ s!^<body>\n?!!;
$content =~ s!</body>\s*\z!!;
print STDOUT $content; # Replace STDOUT with a suitable filehandle
as_HTML
的输出将是语法上正确的HTML,但不一定是格式良好的HTML,供人们查看源代码。如果需要,可以使用HTML::PrettyPrinter写出文件。
答案 1 :(得分:3)
如果代码在您的搜索和替换中很重要,则需要使用HTML::Parser。
这个tutorial看起来比模块的文档更容易理解。
答案 2 :(得分:0)
如果您想使用正则表达式类型方法,并且您已准备好接受以下条件:
<
或>
字符<
或>
字符且不是标记的一部分,则无法使用如果存在上述任何条件,则必须使用其他答案中概述的HTML / XML解析策略之一。
否则:
my $searchfor = "From Argumbay";
my $replacewith = "<a href='http://google.com/?s=Argumbay'>From_Argumbay</a>";
1 while $html =~ s/
\A # beginning of string
( # group all non-searchfor text
( # sub group non-tag followed by tag
[^<]*? # non-tags (non-greedy)
<[^>]*> # whole tags
)*? # zero or more (non-greedy)
)
\Q$searchfor\E # search text
/$1$replacewith/sx;
请注意,如果$searchfor
与$replacetext
匹配,则无法执行此操作(因此请勿将“从Argumbay”添加回替换文本中)。