我有标量中的 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
Run Code Online (Sandbox Code Playgroud)
URL 的服务器部分可以是任何内容(因此不一定是“www”)。我希望将所有指向 olddomain.com 的图像 URL 替换为 newdomain.com,但前提是该图像存在于 newdomain.com 上。所以我不能简单地进行直接替换,而是需要调用一个函数(进行必要的检查)。所以我想我会做这样的事情:
$code =~ s/src=\"(.+?\.olddomain\.com\/.+?)\"/URLReplace($1)/gsie;
Run Code Online (Sandbox Code Playgroud)
URLReplace 是一个执行所有检查并在必要时替换 URL 的函数。问题是正则表达式找到两个匹配项:
http://www.olddomain.com/image1.jpg
Run Code Online (Sandbox Code Playgroud)
和
http://www.otherdomain.com/image2.jpg">\n<img src="http://www.olddomain.com/image3.jpg
Run Code Online (Sandbox Code Playgroud)
问题当然是第一个.+?捕获了直到下一个“.olddomain.com”的所有内容,在第二个匹配中,它是 .olddomain.com http://www.somedomain.com/image2.jpg">\n<img src="http://www。
那么我该如何解决这个问题呢?
您可以使用 DOM 来更改 HTML,而不是使用正则表达式。Mojo::DOM 支持 CSS 选择器来匹配属性中的子字符串。找到要更改的节点后,您可以使用 Mojo::URL(或任何 URI 库)的功能来替换主机名:
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;
Run Code Online (Sandbox Code Playgroud)
输出显示域的选择性更新:
<img src="http://server1.newdomain.com/image1.jpg">
<img src="http://server5.otherdomain.com/image2.jpg">
<img src="http://server2.newdomain.com/image3.jpg">
Run Code Online (Sandbox Code Playgroud)
诀窍在于每个阶段都会限制效果,这样您就不会遇到不想更改的文本。您知道您有img带有 a 的标签src,其中包含您想要的子字符串,然后您知道您只处理该src值,然后您知道您只处理hostURL 的部分。
我在Mojolicious Web UserAgents中有大量 DOM 解析和修改的示例。