我正在使用下面的函数来匹配给定文本中的url,并将它们替换为HTML链接。正则表达式工作得很好,但目前我只替换了第一个匹配。

我怎么能替换所有的URL?我想我应该使用exec命令,但我真的不知道如何做到这一点。

function replaceURLWithHTMLLinks(text) {
    var exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/i;
    return text.replace(exp,"<a href='$1'>$1</a>"); 
}

当前回答

这样做的最佳脚本: http://benalman.com/projects/javascript-linkify-process-lin/

其他回答

用链接替换url(一般问题的答案)

问题中的正则表达式漏掉了很多边缘情况。在检测URL时,最好使用专门的库来处理国际域名、新顶级域名(如.museum)、括号和URL内部和末尾的其他标点符号,以及许多其他边缘情况。有关其他问题的解释,请参阅Jeff Atwood的博客文章the Problem With url。

Dan Dascalescu的回答是URL匹配库的最佳总结 (截至2014年2月)


“使正则表达式替换多个匹配”(具体问题的回答)

在正则表达式的末尾添加一个“g”来启用全局匹配:

/ig;

但这只修复了正则表达式只替换第一个匹配的问题。不要使用那个代码。

/**
 * Convert URLs in a string to anchor buttons
 * @param {!string} string
 * @returns {!string}
 */

function URLify(string){
  var urls = string.match(/(((ftp|https?):\/\/)[\-\w@:%_\+.~#?,&\/\/=]+)/g);
  if (urls) {
    urls.forEach(function (url) {
      string = string.replace(url, '<a target="_blank" href="' + url + '">' + url + "</a>");
    });
  }
  return string.replace("(", "<br/>(");
}

简单的例子

对Travis的Linkify()代码进行了一些优化。我还修复了子域类型格式的电子邮件地址不匹配的错误(即example@domain.co.uk)。

此外,我改变了String类的原型实现,这样项目就可以像这样匹配:

var text = 'address@example.com';
text.linkify();

'http://stackoverflow.com/'.linkify();

不管怎样,这是剧本:

if(!String.linkify) {
    String.prototype.linkify = function() {

        // http://, https://, ftp://
        var urlPattern = /\b(?:https?|ftp):\/\/[a-z0-9-+&@#\/%?=~_|!:,.;]*[a-z0-9-+&@#\/%=~_|]/gim;

        // www. sans http:// or https://
        var pseudoUrlPattern = /(^|[^\/])(www\.[\S]+(\b|$))/gim;

        // Email addresses
        var emailAddressPattern = /[\w.]+@[a-zA-Z_-]+?(?:\.[a-zA-Z]{2,6})+/gim;

        return this
            .replace(urlPattern, '<a href="$&">$&</a>')
            .replace(pseudoUrlPattern, '$1<a href="http://$2">$2</a>')
            .replace(emailAddressPattern, '<a href="mailto:$&">$&</a>');
    };
}

如果你需要显示更短的链接(仅域),但具有相同的长URL,你可以尝试我对Sam Hasler的代码版本上面发布的修改

function replaceURLWithHTMLLinks(text) {
    var exp = /(\b(https?|ftp|file):\/\/([-A-Z0-9+&@#%?=~_|!:,.;]*)([-A-Z0-9+&@#%?\/=~_|!:,.;]*)[-A-Z0-9+&@#\/%=~_|])/ig;
    return text.replace(exp, "<a href='$1' target='_blank'>$3</a>");
}

首先,滚动自己的regexp来解析url是一个糟糕的想法。您必须想象这是一个足够常见的问题,根据rfc,有人已经为它编写、调试和测试了一个库。URI是复杂的——查看Node.js中URL解析的代码和关于URI方案的维基百科页面。

在解析URL时,有大量的边缘情况:国际域名,实际的(.museum)和不存在的(.etc)顶级域名,奇怪的标点符号(包括括号),URL末尾的标点符号,IPV6主机名等。

我已经查看了大量的库,尽管有一些缺点,但还是有一些值得使用:

Soapbox的linkify已经投入了大量精力,2015年6月的一次重大重构删除了jQuery依赖项。它仍然存在idn问题。 AnchorMe是一个自称更快更精简的新产品。还有一些IDN问题。 Autolinker.js列出了非常具体的特性(例如:将正确处理HTML输入。该实用程序不会改变anchor()标签内的href属性”)。当演示版本可用时,我将对其进行一些测试。

我很快就取消了这个任务的库:

Django的urlize不能正确处理某些tld(以下是官方列出的有效tld)。没有演示。 autolink-js不会检测“www.google.com”没有http://,,所以它不太适合自动链接“随意的url”(没有方案/协议)在纯文本中找到。 本·阿尔曼的链接自2009年以来就没有维护过。

如果坚持使用正则表达式,最全面的是Component中的URL regexp,尽管它会错误地检测到一些不存在的双字母tld。