代码之家  ›  专栏  ›  技术社区  ›  wmac

正则表达式用于匹配文本中不属于html标记的URL

  •  0
  • wmac  · 技术社区  · 5 年前

    我使用以下正则表达式将文本中的纯URL替换为html链接:

    preg_replace('/(http[s]{0,1}\:\/\/\S{4,})\s{0,}/ims', '<a href="$1" target="_blank">$1</a> ', $text_msg);
    

    现在我想修改正则表达式,只有当URL后面没有双引号,因此不是标签的一部分时(即URL位于字符串的开头、行的开头或空格之后),它才会替换URL。

    示例:

    • 这是链接 <a href="http://test.com"> …(URL不应被替换)

    • http://test.com (应替换一行开头或整个多行字符串)

    • 这是网站: http://test.com (应替换URL)

    谢谢。

    0 回复  |  直到 5 年前
        1
  •  0
  •   Sherif    5 年前

    你的问题实际上可以分解为两个较小的问题。您已经解决了其中一个问题,即使用正则表达式解析URL。第二部分是从HTML中提取文本,这根本不容易用正则表达式来解决。您遇到的困惑是,试图用正则表达式同时完成这两项任务(解析HTML和解析URL)。请参阅 parsing HTML with regex SO Answer 了解更多关于为什么这是个坏主意的细节。

    所以,让我们使用一个HTML解析器(比如 DOMDocument )从HTML中提取文本节点,并解析这些文本节点内的URL。

    这里有一个例子

    <?php
    $html = <<<'HTML'
        <p>This is a URL http://abcd/ims in text</p>
    HTML;
    
    $dom = new DOMDocument;
    $dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
    
    // Let's walk the entire DOM tree looking for text nodes
    function walk(DOMNode $node, $skipParent = false) {
        if (!$skipParent) {
            yield $node;
        }
        if ($node->hasChildNodes()) {
            foreach ($node->childNodes as $n) {
                yield from walk($n);
            }
        }
    }
    
    foreach (walk($dom->firstChild) as $node) {
        if ($node instanceof DOMText) {
            // lets find any links and change them to HTML
            if (preg_match('/(http[s]{0,1}\:\/\/\S{4,})\s{0,}/ims', $node->nodeValue, $match)) {
    
                $node->nodeValue = preg_replace('/(http[s]{0,1}\:\/\/\S{4,})\s{0,}/ims', "\xff ",
                                                $node->nodeValue);
                $nodeSplit = explode("\xff", $node->nodeValue, 2);
                $node->nodeValue = $nodeSplit[1];
                $newNode = $dom->createTextNode($nodeSplit[0]);
                $href = $dom->createElement('a', $match[1]);
                $href->setAttribute('href', $match[1]);
                $node->parentNode->insertBefore($newNode, $node);
                $node->parentNode->insertBefore($href, $node);
            }
        }
    }
    
    echo $dom->saveHTML();
    

    这将为您提供所需的HTML作为输出:

    <p>This is a URL <a href="http://abcd/ims">http://abcd/ims</a> in text</p>