在我的论坛上,我想自动将 rel =“nofollow”添加到指向外部网站的链接。例如,某人使用以下文本创建帖子:
Link 1: <a href="http://www.external1.com" target="_blank">External Link 1</A>
Link 2: <a href="http://www.myforum.com">Local Link 1</A>
Link 3: <a href="http://www.external2.com">External Link 2</A>
Link 4: <a href="http://www.myforum.com/test" ALT="Local">Local Link 2</A>
使用Perl,我希望将其更改为:
Link 1: <a href="http://www.external1.com" target="_blank" rel="nofollow">External Link 1</A>
Link 2: <a href="http://www.myforum.com">Local Link 1</A>
Link 3: <a href="http://www.external2.com" rel="nofollow">External Link 2</A>
Link 4: <a href="http://www.myforum.com/test" ALT="Local">Local Link 2</A>
我可以使用相当多的代码来完成这项工作,但我希望我可以使用一个或多个正则表达式执行此操作。但我无法弄清楚如何。
答案 0 :(得分:1)
正则表达式可以在有限的场景中工作,但是你永远不应该使用正则表达式来解析HTML
每当你试图用正则表达式解析HTML时,邪恶的孩子就会为处女的鲜血哭泣,而俄罗斯的黑客会把你的webapp用来。
我非常喜欢Mojo套件,因为这允许我们使用非常少的代码使用正确的解析器。我们可以使用CSS选择器来找到有趣的元素:
use strict; use warnings;
use autodie;
use Mojo;
use File::Slurp;
for my $filename (@ARGV) {
my $dom = Mojo::DOM->new(scalar read_file $filename);
for my $link ($dom->find('a[href]')->each) {
$link->attr(rel => 'nofollow')
if $link->attr('href') !~ m(\Ahttps?://www[.]myforum[.]com(?:/|\z));
}
write_file "$filename~", "$dom";
rename "$filename~" => $filename;
}
调用:perl mark-links-as-nofollow.pl *.html
对数据进行测试会产生输出:
Link 1: <a href="http://www.external1.com" rel="nofollow" target="_blank">External Link 1</a>
Link 2: <a href="http://www.myforum.com">Local Link 1</a>
Link 3: <a href="http://www.external2.com" rel="nofollow">External Link 2</a>
Link 4: <a alt="Local" href="http://www.myforum.com/test">Local Link 2</a>
为什么我使用临时文件和rename
?在大多数文件系统上,文件可以原子方式重命名,而写入文件则需要一些时间。所以其他进程可能会看到半文件。
答案 1 :(得分:0)
我会使用正则表达式gobal和eval标志进行回调,例如:
#!/usr/bin/perl
use strict;
my $internal_link = qr'href="https?:\/\/(?:www\.)?myforum\.com';
my $html = '
Lorem ipsum
<a href="http://www.external1.com" target="_blank">External Link 1</A>
Lorem ipsum
<a href="http://www.myforum.com">Local Link 1</A>
Lorem ipsum
<a href="http://www.external2.com">External Link 2</A>
Lorem ipsum
<a href="http://www.myforum.com/test" ALT="Local">Local Link 2</A>
';
$html =~ s/<a ([^>]+)>/"<a ". replace_externals($1). ">"/eg;
print $html;
sub replace_externals {
my ($inner) = @_;
return $inner =~ $internal_link ? $inner : "$inner rel=\"nofollow\"";
}
或者你肯定可以使用negative look-aheads,但那只会弄乱可读性。