2

以下は、Perl コードの小さいながらも機能的なスニペットです。

my $content = qq{<img src='h};
if ($content =~ m{src=(?!('*)http://)}) {
   print "Match '$1'\n";
}
else {
   print "No match\n";
}

印刷します

Match '''

つまり、負の先読み内の正規表現 ('*) が実際にキャプチャされ、' が含まれています。

ただし、最初の行を次のように置き換えると

my $content = qq{<img src='i};

スクリプトが印刷されます

Match ''

つまり、正規表現全体が一致したにもかかわらず、' がキャプチャされていません。

誰が違いを説明できますか? ' が常にキャプチャされるようにするにはどうすればよいですか (これはもちろん、実際のケースを簡略化したものです)。

前もって感謝します

補遺

これがraina77owの全貌です。アイデアは、img タグの src 属性の内容を置き換えることです。次の規則が適用されます。

  1. 内容が ' で始まる場合、' で終わる必要があります。
  2. 内容が「」で始まる場合は、「」で終わる必要があります。
  3. 内容は引用されていない可能性があります。
  4. コンテンツ (引用符の後に) が http:// で始まる場合は、そのままにしておく必要があります。それ以外の場合は、URL の最後のコンポーネント (画像ファイル名) を保持し、前の部分を smth に置き換える必要があります。

もともと私は次の正規表現を使いたかったのです(これはあなたが提案したものと実質的に同じです)

$content =~ s{<\s*img\s+(.*?)src\s*=\s*(["']*)(?!http://).*?([^/"']+)\2(\s+[^>]+)*>}
             {'<img ' . $1 . 'src="' . 'SMTH' . $3 . '"' . $4 . '>'}sgie;

しかし、何らかの理由で文字列と一致します

[img src=' http://qq.com/img.gif ' /]

(山かっこは角かっこに置き換えられます)。

ただし、' の後に http:// が続くため、そうすべきではありません。使用する

$content =~ s{<\s*img\s+(.*?)src\s*=\s*(["'])*(?!http://).*?([^/"']+)\2(\s+[^>]+)*>}
             {'<img ' . $1 . 'src="' . 'SMTH' . $3 . '"' . $4 . '>'}sgie;

この場合 \2 は空の文字列と一致しないため、これも不適切です。

修正できないので、回避策を探すことにしました。ああ...

4

2 に答える 2

4

堅牢なHTMLパーサー/ライブラリを使用して質問の4つのルールを適用します。

use strictures;
use URI qw();
use Web::Query qw();
my $w = Web::Query->new_from_html(<<'HTML');
<html><head></head><body>
<img src='http://example.com'>
<img src="http://example.com">
<img src=http://example.com>
<img src='foo/bar/baz.png'>
<img src="foo/bar/baz.png">
<img src=foo/bar/baz.png>
</body></html>
HTML

$w->find('img')->each(sub {
    my (undef, $img) = @_;
    my $u = URI->new($img->attr('src'));
    unless ($u->scheme) {   # skip absolute URIs
        $u->path_segments('SMTH', ($u->path_segments)[-1]);
        $img->attr('src', $u);
    }
});
print $w->html;
于 2012-06-18T13:24:02.807 に答える
1

まあ、それを修正するのはとても簡単です:

my $content = qq{<img src='h};
if ($content =~ m{src=('*)(?!http://)}) {
   print "Match '$1'\n";
}
else {
   print "No match\n";
}

しかし、あなたが説明したバグを説明するのは別の話です(そして、それは本当に Perl 正規表現エンジンのバグだと思います('*)。)'h'i

更新:クトゥルフの方法に提出して申し訳ありませんが、このコードはあなたが要求したことを実行する可能性があります:

sub correct { # just an example
  my $orig = shift;
  $orig =~ s/\.gif$/\.jpg/;
  return $orig;
}

my $img = "<img src='http://localhost.com/pic.gif' />";
$img =~ s{
  (< \s* img \s+ src \s* = \s*)
  (["']?)
  ([^ '">]+)
  \2
}{ 
  $1 . $2 . ( substr($3, 0, 7) eq 'http://' ?  $3  : correct $3 ) . $2
}xe;

print $img;

それでも、HTML パーサーを使用した方がよいと答えた人は、いずれも最大の手がかりを得たと思います。)

于 2012-06-18T10:51:38.717 に答える