【问题标题】:Extract URL from string从字符串中提取 URL
【发布时间】:2011-05-22 09:24:03
【问题描述】:

我正在尝试找到一种可靠的解决方案来从字符串中提取 url。我有一个网站,用户可以在其中回答问题,并在来源框中输入他们的信息来源,我允许他们输入网址。我想提取该网址并使其成为超链接。类似于 Yahoo Answers 的做法。

有谁知道可以做到这一点的可靠解决方案吗?

我发现的所有解决方案都适用于某些 URL,但不适用于其他 URL。

谢谢

【问题讨论】:

    标签: php regex url preg-replace


    【解决方案1】:

    John Gruber 拥有spent a fair amount of time 完善了“一个正则表达式来统治所有这些”以进行链接检测。使用preg_replace() 如其他答案中所述,使用以下正则表达式应该是检测链接的最准确(如果不是最准确)方法之一:

    (?i)\b((?:[a-z][\w-]+:(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))
    

    如果你只想匹配 HTTP/HTTPS:

    (?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))
    

    【讨论】:

    • 正是我想要的!谢谢。
    • 对于任何希望将所有子模式转换为非捕获并且正斜杠转义的人:\b(?:(?:[az][\w-]+:(?: \/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][az]{2, 4}\/)(?:[^\s()]+|((?:[^\s()]+|(?:([^\s()]+)) )*))+(?:((?:[^\s()]+|(?:([^\s()]+)))*)|[^\s`!( )[]{};:'".,?«»“”'']))
    • TLD 可能有超过 4 个字符,请参阅:iana.org/domains/root/db
    • 我们如何在 preg 中使用这个正则表达式?我的意思是,因为它有 "' 代码不能正常工作,比如:preg_match('(?i)\b......]))', $str) - 所有代码似乎都被注释了。
    • 不工作。 Preg_match 和 preg_match_all 每次都失败,即使在删除单引号/双引号后也是如此
    【解决方案2】:
    $string = preg_replace('/https?:\/\/[^\s"<>]+/', '<a href="$0" target="_blank">$0</a>', $string);
    

    它只匹配 http/https,但这确实是您想要转换为链接的唯一协议。如果你想要其他人,你可以这样改变它:

    $string = preg_replace('/(https?|ssh|ftp):\/\/[^\s"]+/', '<a href="$0" target="_blank">$0</a>', $string);
    

    【讨论】:

    • 您可能还想排除 &lt; 或在匹配的字符串上应用 htmlspecialchars 以避免代码注入。
    • 很好,但是如果您查看表达式,它允许除空格和" 之外的任何内容。我相信这消除了任何 HTML 注入。
    • Bron:不,您使用的匹配值不仅作为属性值,还作为元素文本内容。
    【解决方案3】:

    url 有很多边缘情况。像 url 可以包含括号或不包含协议等。这就是为什么正则表达式是不够的。

    我创建了一个可以处理大量边缘情况的 PHP 库:Url highlight

    您可以从字符串中提取网址或直接突出显示它们。
    示例:

    <?php
    
    use VStelmakh\UrlHighlight\UrlHighlight;
    
    $urlHighlight = new UrlHighlight();
    
    // Extract urls
    $urlHighlight->getUrls("This is example http://example.com.");
    // return: ['http://example.com']
    
    // Make urls as hyperlinks
    $urlHighlight->highlightUrls('Hello, http://example.com.');
    // return: 'Hello, <a href="http://example.com">http://example.com</a>.'
    

    更多详情请见readme。对于覆盖的 url 案例,请参阅test

    【讨论】:

      【解决方案4】:

      雅虎!当链接写得正确并与其他文本分开时,Answers 可以很好地识别链接,但它不能很好地分离尾随标点符号。例如The links are @987654321@, @987654322@, and @987654323@. 将在前两个中包含逗号,在第三个中包含句点。

      但如果这是可以接受的,那么像这样的模式应该这样做:

      \<http:[^ ]+\>
      

      看起来stackoverflow的解析器更好。是开源的吗?

      【讨论】:

      • 更聪明,但仍不完美。错过了 ssh+svn 之类的东西。
      【解决方案5】:

      这段代码对我有用。

      function makeLink($string){
      
      /*** make sure there is an http:// on all URLs ***/
      $string = preg_replace("/([^\w\/])(www\.[a-z0-9\-]+\.[a-z0-9\-]+)/i", "$1http://$2",$string);
      /*** make all URLs links ***/
      $string = preg_replace("/([\w]+:\/\/[\w-?&;#~=\.\/\@]+[\w\/])/i","<a target=\"_blank\" href=\"$1\">$1</a>",$string);
      /*** make all emails hot links ***/
      $string = preg_replace("/([\w-?&;#~=\.\/]+\@(\[?)[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2,3}|[0-9]{1,3})(\]?))/i","<a href=\"mailto:$1\">$1</a>",$string);
      
      return $string;
      }
      

      【讨论】:

      猜你喜欢
      • 2011-08-30
      • 1970-01-01
      • 2012-06-07
      • 1970-01-01
      • 2011-01-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多