【问题标题】:PHP Regex/str_replace strange non-matchPHP Regex/str_replace 奇怪的不匹配
【发布时间】:2016-06-14 14:08:00
【问题描述】:

这有点让我困惑,我似乎不明白为什么http://www.example.com/a/b/c 会返回https://example.net//b/c - 最好的猜测是它与第一场比赛冲突,但为什么呢?

代码:

 $contents = '
<a href="http://www.example.com/a">Works</a>
<a href="http://www.example.com/a/b/c">Doesnt Work</a>
<a href="http://www.example.com/x/y/z">Works</a>';


            $regexp = "/<a\s[^>]*href=\"([^\"]*)\"[^>]*>(.*)<\/a>/siU";
            if(preg_match_all($regexp, $contents, $matches, PREG_SET_ORDER)) {
                foreach($matches as $match) {
                    print_r($match);
                    if (!empty($match[1])) { 
                        $urlString = 'https://www.example.net/newlink/';
                        $contents = str_replace($match[1], $urlString, $contents);
                    }
                }
            }

echo $contents;

输出:

Array
(
    [0] => <a href="http://www.example.com/a">Works</a>
    [1] => http://www.example.com/a
    [2] => Works
)
Array
(
    [0] => <a href="http://www.example.com/a/b/c">Doesnt Work</a>
    [1] => http://www.example.com/a/b/c
    [2] => Doesnt Work
)
Array
(
    [0] => <a href="http://www.example.com/x/y/z">Works</a>
    [1] => http://www.example.com/x/y/z
    [2] => Works
)

    <a href="https://www.example.net/newlink/">Works</a>
    <a href="https://www.example.net/newlink//b/c">Doesnt Work</a>
    <a href="https://www.example.net/newlink/">Works</a>

https://eval.in/528426

【问题讨论】:

  • preg_replace_callback 中进行操作。问题是在第一次迭代期间在 $contents 中完成了 2 次替换,因为有 2 个 http://www.example.com/a 子字符串。
  • 谢谢,会调查那个解决方案。

标签: php regex html-parsing


【解决方案1】:

查看str_replace()的手册

它用https://www.example.net/newlink/替换了两次出现的http://www.example.com/a
然后找不到http://www.example.com/a/b/c,因为此时它是https://www.example.net/newlink//b/c

编辑:这应该有效:$contents = str_replace('"'.$match[1].'"', '"'.$urlString.'"', $contents); // 在搜索/替换中包含引号

【讨论】:

    【解决方案2】:

    问题是在第一次迭代期间在 $contents 中执行了 2 次替换,因为有 2 个 http://www.example.com/a 子字符串。

    一种可能的解决方案是使用preg_replace_callback 来匹配捕获您需要保留的所有部分并仅匹配您需要替换的部分的子字符串:

    IDEONE demo

    $contents = '<a href="http://www.example.com/a">Works</a>
    <a href="http://www.example.com/a/b/c">Doesnt Work</a>
    <a href="http://www.example.com/x/y/z">Works</a>';
    $regexp = "/(<a\s[^>]*href=\")[^\"]*(\"[^>]*>.*<\/a>)/siU";
    $contents = preg_replace_callback($regexp, function($m) {
      return $m[1] . 'https://www.example.net/newlink/' . $m[2];
    }, $contents);
    echo $contents;
    

    但是,如果您正在处理 HTML,我宁愿使用基于 DOM 的解决方案。 以下是如何将所有链接设置为指向https://www.example.net/newlink/

    $html = <<<DATA
    <a href="http://www.example.com/a">Works</a>
    <a href="http://www.example.com/a/b/c">Doesnt Work</a>
    <a href="http://www.example.com/x/y/z">Works</a>
    DATA;
    
    $dom = new DOMDocument('1.0', 'UTF-8');
    $dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
    
    $xpath = new DOMXPath($dom);
    $links = $xpath->query('//a');
    
    foreach($links as $link) { 
       $link->setAttribute('href', 'https://www.example.net/newlink/');
    }
    echo $dom->saveHTML();
    

    another demo

    【讨论】:

    • 谢谢!第一个解决方案没有完成 。虽然我明白你的意思,但再次感谢。
    • 对不起,我忘了我从内部值中删除了捕获组。因此,$m[3] 应替换为 $m[2]。这就是解决方案 1 所需的所有修复。我刚刚更新了答案。如果你有一个普通的 HTML 文档,而不仅仅是一串标签,第二个演示会很好地工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-27
    • 2019-12-07
    • 1970-01-01
    相关资源
    最近更新 更多