Regex Perl:替换满足特定条件的链接(html)

Regex Perl:替换满足特定条件的链接(html),regex,perl,Regex,Perl,在我的论坛上,我想自动添加指向外部站点的链接。例如,有人用以下文本创建帖子: 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">E

在我的论坛上,我想自动添加指向外部站点的链接。例如,有人用以下文本创建帖子:

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>
链接1:
链接2:
链接3:
链接4:
使用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>
链接1:
链接2:
链接3:
链接4:

我可以使用相当多的代码行来实现这一点,但我希望我可以使用一个或多个正则表达式来实现这一点。但是我不知道怎么做。

我会使用regex 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\"";
}
#/usr/bin/perl
严格使用;
我的$internal\u link=qr'href=“https?:\/\/(?:www\)?我的论坛\.com';
我的$html
乱数假文
乱数假文
乱数假文
乱数假文
';

$html=~s/,但这只会破坏可读性。

正则表达式可以在有限的场景中工作,但决不能使用正则表达式解析html

每次你试图用正则表达式解析HTML时,邪恶的孩子都会为处女的鲜血而哭泣,而俄罗斯黑客会破坏你的网络应用程序

    — 从

我非常喜欢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>
链接1:
链接2:
链接3:
链接4:
为什么我要使用tempfiles和
重命名
?在大多数文件系统中,文件可以自动重命名,而写入文件需要一些时间。因此其他进程可能会看到半写文件


您是否允许在帖子中使用任意HTML?或者您是否使用其他标记语言,如BB代码–在这种情况下,增强解析器可能会更好。我确实不熟悉Perl,但会使用类似以下内容:(*?href=/)http:////www/.myforum/.com/".*?)(.*?>.*)“做你的正则表达式,如果匹配,它是本地的,否则就不是。如果不是,请找到“(.*?href=.*?(>.*)”,并用第一个元素“+”rel=/“nofollow/”+第二个元素替换您找到的内容?@amon:是的,论坛使用标记语言,但帖子以HTML形式存储。@AlexBaldwin:只有当字符串中只有一个链接时,这才有效。@ClarkVentura,你说得对。我试图用给出的例子让它工作,但没有注意到他提到的现实世界的问题。但是,如果再加上一个只查找所有链接的正则表达式,那么您就可以在找到的每个链接上使用我的旧正则表达式了!我以前从未在regex中使用过evals,但看起来它应该工作得很好!谢谢顺便说一句,我已经尝试过用负面的外观来做,但是没有成功(因为它会跳过非本地链接,直到找到一个本地链接并将两个链接混合在一起——很难解释,但是如果你尝试,你会明白我的意思)。