perl 当我不知道子域名时,如何在HTML中替换域名?

5lhxktic  于 8个月前  发布在  Perl
关注(0)|答案(3)|浏览(89)

我有一个标量中的HTML代码。HTML代码可以包含我想要替换的某个域的URL。例如:

my $code = <<ENDCODE;
  <img src="http://server1.olddomain.com/image1.jpg">
  <img src="http://server5.otherdomain.com/image2.jpg">
  <img src="http://server2.olddomain.com/image3.jpg">
ENDCODE

URL的服务器部分可以是任何东西(所以不一定是“www”)。我希望将所有指向www.example.com的图像URL替换为newdomain.com,但前提是图像存在于newdomain.com上。所以我不能简单地直接替换,而是需要调用一个函数(执行必要的检查)。所以我想我会这样做:olddomain.com

$code =~ s/src=\"(.+?\.olddomain\.com\/.+?)\"/URLReplace($1)/gsie;

URLReplace是一个函数,它会执行所有检查并在必要时替换URL。问题是正则表达式会找到两个匹配项:

http://www.olddomain.com/image1.jpg

http://www.otherdomain.com/image2.jpg">\n<img src="http://www.olddomain.com/image3.jpg

当然,问题是第一个.+?捕获了下一个“. olddomain.com“之前的所有内容,在第二个匹配中,它是http://www.somedomain.com/image2.jpg">\n<img src="http://www
那么我该如何解决这个问题呢?

oxf4rvwz

oxf4rvwz1#

除了正则表达式,你可以使用DOM来改变HTML。Mojo::DOM支持CSS选择器来匹配属性中的子字符串。一旦你找到了你想要改变的节点,你可以使用Mojo::URL(或任何URI lib)的功能来替换主机名:

use v5.10;
use Mojo::DOM;
use Mojo::URL;

my $code = <<~'ENDCODE';
  <img src="http://server1.olddomain.com/image1.jpg">
  <img src="http://server5.otherdomain.com/image2.jpg">
  <img src="http://server2.olddomain.com/image3.jpg">
ENDCODE

my $dom = Mojo::DOM->new($code);

my $old = ".olddomain.com";
$dom->find( "img[src*=$old]" )
    ->each( sub {
        my $url = Mojo::URL->new($_->attr('src'));
        return unless $url->host =~ m/\Q$old\E\z/;
        $url->host(  $url->host =~ s/\Q$old\E\z/\.newdomain.com/r );
        $_->attr( src => $url );
        } )
    ;

say $dom;

输出显示了域的选择性更新:

<img src="http://server1.newdomain.com/image1.jpg">
<img src="http://server5.otherdomain.com/image2.jpg">
<img src="http://server2.newdomain.com/image3.jpg">

诀窍在于每个阶段都会限制效果,这样你就不会遇到你不想改变的文本。你知道你有一个srcimg标签,它有你想要的子字符串,然后你知道你只处理src值,然后你知道你只处理URL的host部分。
我有很多Mojolicious Web UserAgents中DOM解析和修改的例子。

cmssoen2

cmssoen22#

如果不想让.匹配换行符,就不要使用/s
使用.通常过于笼统。如果您知道URL被双引号包围,则可以将其替换为[^"]

s/src="([^"]+\.olddomain\.com\/[^"]+)"/.../
kcrjzv8t

kcrjzv8t3#

我找到了一个解决方案:
因使用

s/src=\"(.+?\.olddomain\.com\/.+?)\"/URLReplace($1)/gsie;

我应该用

s/src=\"([^\.]+?\.olddomain\.com\/.+?)\"/URLReplace($1)/gsie;

不同之处在于,我现在使用[^\.],而不是.(匹配任何字符),它匹配任何字符 * 但 * 点。所以它在遇到第一个点时停止匹配。

相关问题