如何用链接替换普通URL?

Ser*_*Amo 433 javascript regex

我使用下面的函数来匹配给定文本中的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>"); 
}
Run Code Online (Sandbox Code Playgroud)

Dan*_*scu 336

首先,滚动自己的正则表达式来解析URL是一个糟糕的主意.根据RFC,你必须想象这是一个常见的问题,有人为它编写,调试和测试了一个库.URI很复杂 - 请查看Node.js中的URL解析代码URI方案的Wikipedia页面.

在解析URL方面有很多边缘案例:国际域名,实际(.museum)与不存在(.etc)TLD,包括括号的奇怪标点符号,URL末尾的标点符号,IPV6主机名等.

我已经看了一吨图书馆,并有几个值得使用,尽管一些缺点:

我已经快速取消了这项任务资格的图书馆:

如果你坚持使用正则表达式,那么最全面的是来自ComponentURL regexp,尽管它会通过查看错误地检测到一些不存在的双字母TLD.

  • 遗憾的是,来自Component的"URL regexp"没有被评论,对它正在做什么的一些解释会有所帮助.`Autolinker.js`评论很好并且有测试.在[Vebjorn Ljosa的答案](http://stackoverflow.com/a/10498205/2541)中链接的`urlize.js`库看起来也很有特色并且维护得很好,尽管它没有测试. (3认同)
  • 很奇怪没有人提到John Gruber维护[URL正则表达式模式]的努力(http://daringfireball.net/2010/07/improved_regex_for_matching_urls).它不是解决问题的唯一/理想解决方案,但无论如何都值得研究,如果您正在推出自己的解决方案.只想添加此作为参考. (2认同)
  • @DanDascalescu看看这个http://markdown-it.github.io/linkify-it/.该库完全专注于一项任务 - 检测文本中的链接模式.但我希望,它做得很好.例如,它具有正确的unicode支持,包括星体字符.它支持国际顶级域名. (2认同)
  • Autolinker.js 加 1,易于实现,快速的解决方案,如果您正在寻找的话。谢谢 (2认同)

Sam*_*ler 285

用链接替换URL(回答一般问题)

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

URL匹配库最佳摘要Dan Dascalescu的答案中+100
(截至2014年2月)


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

在正则表达式的末尾添加"g"以启用全局匹配:

/ig;
Run Code Online (Sandbox Code Playgroud)

但这只能解决正则表达式只替换第一个匹配的问题.不要使用该代码.


小智 146

我对Travis的代码进行了一些小修改(只是为了避免任何不必要的重新声明 - 但它对我的需求非常有用,非常好!):

function linkify(inputText) {
    var replacedText, replacePattern1, replacePattern2, replacePattern3;

    //URLs starting with http://, https://, or ftp://
    replacePattern1 = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim;
    replacedText = inputText.replace(replacePattern1, '<a href="$1" target="_blank">$1</a>');

    //URLs starting with "www." (without // before it, or it'd re-link the ones done above).
    replacePattern2 = /(^|[^\/])(www\.[\S]+(\b|$))/gim;
    replacedText = replacedText.replace(replacePattern2, '$1<a href="http://$2" target="_blank">$2</a>');

    //Change email addresses to mailto:: links.
    replacePattern3 = /(([a-zA-Z0-9\-\_\.])+@[a-zA-Z\_]+?(\.[a-zA-Z]{2,6})+)/gim;
    replacedText = replacedText.replace(replacePattern3, '<a href="mailto:$1">$1</a>');

    return replacedText;
}
Run Code Online (Sandbox Code Playgroud)

  • 代码中存在与此处的电子邮件地址匹配的错误.`[a-zA-Z] {2,6}`应该读一下`(?:[a-zA-Z] {2,6})+`的内容,以便匹配更复杂的域名,即email@example.co.uk. (5认同)
  • 我希望我可以给你一个以上的upvote :) (3认同)
  • 没有 `http://` 或 `www` 的 URL 怎么样?这对那些类型的 URL 有效吗? (2认同)
  • 我尝试编辑原始帖子来修复mailto问题,但我必须添加至少6个字符才能进行编辑.但是如果你改变这一行:`replacePattern3 = /(\ w + @ [a-zA-Z _] +?\.[a-zA-Z] {2,6})/ gim;`用这个`replacePattern3 = /(\w + @ [a-zA-Z _] +?(\.[a-zA-Z] {2,6})+)/ gim;`修复了mailto问题:) (2认同)

Ros*_*mbo 67

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

另外,我将实现更改为String类的原型,以便可以像这样匹配项:

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

'http://stackoverflow.com/'.linkify();
Run Code Online (Sandbox Code Playgroud)

无论如何,这是脚本:

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>');
    };
}
Run Code Online (Sandbox Code Playgroud)

  • 它不适用于电子邮件用户名中的“+”,例如“foo+bar@domain.com”。我用电子邮件模式`/[\w.+]+@[a-zA-Z_-]+?(?:\.[a-zA-Z]{2,6})+/gim`(注意第一个括号中的`+`),但我不知道这是否会破坏其他内容。 (2认同)

Tra*_*vis 23

谢谢,这非常有帮助.我还想要一些可以链接看似URL的东西的东西 - 作为一个基本要求,即使http://协议前缀不存在,它也会像www.yahoo.com这样链接.所以基本上,如果"www." 它存在,它将链接它并假设它是http://.我还希望电子邮件变成mailto:links.示例:www.yahoo.com将转换为www.yahoo.com

这是我最终得到的代码(这个页面的代码和我在网上找到的其他东西的组合,以及我自己做的其他东西):

function Linkify(inputText) {
    //URLs starting with http://, https://, or ftp://
    var replacePattern1 = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim;
    var replacedText = inputText.replace(replacePattern1, '<a href="$1" target="_blank">$1</a>');

    //URLs starting with www. (without // before it, or it'd re-link the ones done above)
    var replacePattern2 = /(^|[^\/])(www\.[\S]+(\b|$))/gim;
    var replacedText = replacedText.replace(replacePattern2, '$1<a href="http://$2" target="_blank">$2</a>');

    //Change email addresses to mailto:: links
    var replacePattern3 = /(\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,6})/gim;
    var replacedText = replacedText.replace(replacePattern3, '<a href="mailto:$1">$1</a>');

    return replacedText
}
Run Code Online (Sandbox Code Playgroud)

在第二次替换中,(^ | [^ /])部分仅替换www.whatever.com,如果它还没有前缀为// - 以避免在第一次替换中已经链接了URL时进行双重链接.此外,www.whatever.com可能位于字符串的开头,这是正则表达式中该部分的第一个"或"条件.

这可以作为jQuery插件集成,如上面所示的Jesse P - 但我特别想要一个不在现有DOM元素上运行的常规函数​​,因为我正在使用我拥有的文本然后将它添加到DOM中,我希望在添加文本之前将文本"链接",因此我将文本传递给此函数.效果很好.

  • 我只是在一个字符串上运行它,其中一些web链接已经有一个href链接.在这种情况下,它无法搞乱现有的工作链接. (2认同)

Veb*_*osa 17

识别URL很棘手,因为它们通常被标点符号包围,并且因为用户经常不使用URL的完整形式.存在许多JavaScript函数用于替换带有超链接的URL,但是我无法找到一个urlize与基于Python的Web框架Django中的过滤器一样好的函数.因此我将Django的urlize函数移植到JavaScript:

https://github.com/ljosa/urlize.js

一个例子:

urlize('Go to SO (stackoverflow.com) and ask. <grin>', 
       {nofollow: true, autoescape: true})
=> "Go to SO (<a href="http://stackoverflow.com" rel="nofollow">stackoverflow.com</a>) and ask. &lt;grin&gt;"
Run Code Online (Sandbox Code Playgroud)

第二个参数,如果为true,则导致rel="nofollow"插入.第三个参数,如果为true,则转义在HTML中具有特殊含义的字符.请参阅自述文件.


Chr*_*och 10

我将Roshambo String.linkify()更改为emailAddressPattern以识别aaa.bbb.@ ccc.ddd地址

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 *** here I've changed the expression ***
        var emailAddressPattern = /(([a-zA-Z0-9_\-\.]+)@[a-zA-Z_]+?(?:\.[a-zA-Z]{2,6}))+/gim;

        return this
            .replace(urlPattern, '<a target="_blank" href="$&">$&</a>')
            .replace(pseudoUrlPattern, '$1<a target="_blank" href="http://$2">$2</a>')
            .replace(emailAddressPattern, '<a target="_blank" href="mailto:$1">$1</a>');
    };
}
Run Code Online (Sandbox Code Playgroud)


deg*_*ate 8

我在谷歌搜索了更新的东西并遇到了这个:

$('p').each(function(){
   $(this).html( $(this).html().replace(/((http|https|ftp):\/\/[\w?=&.\/-;#~%-]+(?![\w\s?&.\/;#~%"=-]*>))/g, '<a href="$1">$1</a> ') );
});
Run Code Online (Sandbox Code Playgroud)

演示: http ://jsfiddle.net/kachibito/hEgvc/1/

适用于普通链接.

  • 我的意思是任何格式为 `http://example.com/folder/folder/folder/` 或 `https://example.org/blah` 等 - 只是你典型的非疯狂 URL 格式,它将匹配 95-99使用案例的百分比。我将它用于内部管理区域,所以我不需要任何花哨的东西来捕捉边缘情况或哈希链接。 (2认同)

Zuh*_*aha 7

/**
 * 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/>(");
}
Run Code Online (Sandbox Code Playgroud)

简单的例子


Art*_*pov 5

如果您需要显示较短的链接(仅域),但具有相同的长 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>");
}
Run Code Online (Sandbox Code Playgroud)


rle*_*mon 5

此解决方案与许多其他解决方案一样,并且实际上使用与其中一个相同的正则表达式,但是它不会返回HTML字符串,而是返回包含A元素和任何适用文本节点的文档片段.

 function make_link(string) {
    var words = string.split(' '),
        ret = document.createDocumentFragment();
    for (var i = 0, l = words.length; i < l; i++) {
        if (words[i].match(/[-a-zA-Z0-9@:%_\+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[-a-zA-Z0-9@:%_\+.~#?&//=]*)?/gi)) {
            var elm = document.createElement('a');
            elm.href = words[i];
            elm.textContent = words[i];
            if (ret.childNodes.length > 0) {
                ret.lastChild.textContent += ' ';
            }
            ret.appendChild(elm);
        } else {
            if (ret.lastChild && ret.lastChild.nodeType === 3) {
                ret.lastChild.textContent += ' ' + words[i];
            } else {
                ret.appendChild(document.createTextNode(' ' + words[i]));
            }
        }
    }
    return ret;
}
Run Code Online (Sandbox Code Playgroud)

有一些警告,即旧的IE和textContent支持.

是一个演示.

  • @DanDascalescu可能会提供你所说的边缘案例,而不是全面覆盖. (2认同)
  • 所以有边缘情况.精彩.这些答案对其他人来说可能仍然有用,而且对它们进行贬低似乎有点矫枉过正.您评论过的其他答案和看似downvoted**确实**包含有用的信息(以及您的答案).不是每个人都会反对所说的案例,并不是每个人都想要使用图书馆. (2认同)