如何用链接replace纯文字的URL?

我正在使用下面的函数来匹配给定文本中的URL,并将其replace为HTML链接。 正则expression式运行良好,但是目前我只replace了第一个匹配项。

我如何可以取代所有的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>"); } 

首先,滚动你自己的正则expression式来parsingURL是一个可怕的想法 。 根据RFC ,你必须想象这是一个常见的问题,有人已经写了,debugging过并且testing了一个库。 URI很复杂 – 查看Node.js中的URLparsing代码和URIscheme中的Wikipedia页面。

parsingURL有很多边界情况: 国际域名 ,实际( .museum )与不存在( .etc )顶级域名(TLD),包括圆括号的奇怪标点符号,URL末尾的标点符号,IPV6主机名等。

我看了很多图书馆 ,有一些值得使用的地方,尽pipe有一些缺点:

  • 肥皂箱的链接已经看到了一些认真的努力,并在2015年6月的一个重要的重构 删除了jQuery的依赖 。 它仍然有IDN的问题 。
  • AnchorMe是一个声称更快 ,更精简的新人。 一些IDN问题也是如此。
  • Autolinker.js非常具体地列出了一些特性(例如: “将正确处理HTMLinput,实用程序不会改变anchor()标签内的href属性” )。 当演示变得可用时,我会对它进行一些testing。

我很快就因为这个任务而失去资格的图书馆:

  • Django的urlize 没有正确处理某些顶级域名 (这里是正式的顶级域名列表, 没有演示 。
  • 自动链接-js不会检测到“www.google.com”没有http://,所以它不太适合用纯文本自动链接“临时URL”(没有scheme/协议)。
  • 本·阿尔曼的联系自2009年以来一直没有维持。

如果你坚持正则expression式,最全面的是来自Component的URL正则expression式,尽pipe它会通过查看它错误地检测到一些不存在的双字母顶级域名。

用链接replaceURL(回答一般问题)

问题中的正则expression式忽略了很多边界情况。 当检测到URL时,最好使用专门的库来处理国际域名,新的顶级域名(如.museum ,圆括号和URL末尾的其他标点符号以及其他许多边缘案例。 请参阅Jeff Atwood的博客文章The URL With URLs来解释其他一些问题。

有关URL匹配库最佳总结Dan Dascalescu的答案中 +100
(截至2014年2月)


“用正则expression式replace多个匹配项”(回答特定问题)

在正则expression式的末尾添加“g”以启用全局匹配:

 /ig; 

但是这只能解决正则expression式只replace第一个匹配的问题。 不要使用该代码。

我已经对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; } 

对上面的Travis的Linkify()代码做了一些优化。 我还修复了一个错误,其中子域名types格式的电子邮件地址不匹配(即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的东西 – 作为一个基本要求,即使没有http://协议前缀,它也会链接诸如www.yahoo.com之类的东西。 所以基本上,如果“www。” 现在,它会链接它,并假设它是http://。 我也想要电子邮件变成mailto:链接。 例如:www.yahoo.com将被转换为www.yahoo.com

这里是我结束的代码(从这个页面的代码和我在网上find的其他东西的组合,以及我自己做的其他的东西):

 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 } 

在第二个replace中,(^ | [^ /])部分只是replacewww.whatever.com,如果它还没有被前缀为//,则为了避免在第一个replace中已经链接了URL的情况下的双重链接。 另外,www.whatever.com可能在string的开头,也就是正则expression式的第一个“或”条件。

这可以被集成为一个jQuery插件,如上面所示的Jesse P – 但是我特别想要一个不在现有DOM元素上运行的常规函数​​,因为我正在将文本添加到DOM中,然后将其添加到DOM中。在添加文本之前,我想让文本“链接”,所以我通过这个函数传递文本。 很好用。

识别URL是非常棘手的,因为它们通常被标点符号包围,并且用户经常不使用完整的URLforms。 现在有很多JavaScript函数可以用超链接代替URL,但是我找不到一个和基于Python的Web框架Django中的urlizefilter一样的urlize 。 因此,我将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;" 

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

我将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>'); }; } 

最好的脚本: http : //benalman.com/projects/javascript-linkify-process-lin/

这个解决scheme和许多其他的一样工作,实际上它们和其中的一个使用相同的正则expression式,但是不是返回一个HTMLstring,而是返回一个包含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}\.[az]{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; } 

有一些警告,即与较旧的IE和textContent的支持。

这里是一个演示。

如果你需要显示较短的链接(只有域),但具有相同的长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>"); } 

把事情简单化! 说出你不能拥有的东西,而不是你能拥有的东西:)

如上所述,URL可能非常复杂,特别是在'?'之后,并不是所有的都以'www'开头。 例如maps.bing.com/something?key=!"£$%^*()&lat=65&lon&lon=20

所以,不要有一个复杂的正则expression式,不会遇到所有的边缘情况,而且很难维护,这个更简单的那个,对我来说在实践中效果不错。

比赛

http(s):// (anything but a space)+

www. (anything but a space)+

哪里有什么东西是基本上是一个贪婪的匹配,继续给你一个空间,报价,尖括号或行尾

也:

请记住检查它是否已经不是URL格式,例如文本包含href="..."src="..."

添加ref = nofollow(如果适用)

这个解决scheme不像上面提到的库那么“好”,但是要简单得多,而且在实践中运行良好。

 if html.match( /(href)|(src)/i )) { return html; // text already has a hyper link in it } html = html.replace( /\b(https?:\/\/[^\s\(\)\'\"\<\>]+)/ig, "<a ref='nofollow' href='$1'>$1</a>" ); html = html.replace( /\s(www\.[^\s\(\)\'\"\<\>]+)/ig, "<a ref='nofollow' href='http://$1'>$1</a>" ); html = html.replace( /^(www\.[^\s\(\)\'\"\<\>]+)/ig, "<a ref='nofollow' href='http://$1'>$1</a>" ); return html; 

我在谷歌search任何更新,并跑过这一个:

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

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

适用于正常的链接。

应该注意关于URI复杂性的警告,但对您的问题的简单回答是:
要replace每个匹配,您需要将/g标志添加到RegEx的末尾:
/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gi

Reg Ex: /(\b((https?|ftp|file):\/\/|(www))[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|]*)/ig

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

下面是一些testing的string:

  1. find我的www.google.com
  2. 万维网
  3. 找我到www。 http://www.com
  4. 跟我来: http : //www.nishantwork.wordpress.com
  5. http://www.nishantwork.wordpress.com
  6. 跟我来: http : //www.nishantwork.wordpress.com
  7. https://stackoverflow.com/users/430803/nishant

注意:如果你不想通过www作为有效的只是使用下面的reg例如: /(\b((https?|ftp|file):\/\/|(www))[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig

正确的URL检测与国际域名和星界的支持是不平凡的事情。 linkify-it从许多条件build立正则expression式,最终的大小约为6千字节:)。 它比所有的库更准确,目前在接受的答案中引用。

看到linkify它演示检查现场所有边缘案件和testing你的。

如果您需要链接HTML源代码,则应先parsing它,然后分别迭代每个文本标记。

我不得不做相反的事情,并把html链接到URL中,但是我修改了你的正则expression式,它像一个魅力,感谢:)

 var exp = /<a\s.*href=['"](\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_ |:!。。,;] * [ -  A-Z0-9 + @#\ /%=〜_ |])[“'] *> * <\ / A> / IG;

 source = source.replace(exp,“$ 1”);

Travitron上面的答案的电子邮件检测不适用于我,所以我扩展/replace它以下(C#代码)。

 // Change e-mail addresses to mailto: links. const RegexOptions o = RegexOptions.Multiline | RegexOptions.IgnoreCase; const string pat3 = @"([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,6})"; const string rep3 = @"<a href=""mailto:$1@$2.$3"">$1@$2.$3</a>"; text = Regex.Replace(text, pat3, rep3, o); 

这允许电子邮件地址,如“ firstname.secondname@one.two.three.co.uk ”。

从几个来源input后,我现在有一个很好的解决scheme。 这与编写自己的replace代码有关。

回答 。

小提琴 。

 function replaceURLWithHTMLLinks(text) { var re = /(\(.*?)?\b((?:https?|ftp|file):\/\/[-a-z0-9+&@#\/%?=~_()|!:,.;]*[-a-z0-9+&@#\/%=~_()|])/ig; return text.replace(re, function(match, lParens, url) { var rParens = ''; lParens = lParens || ''; // Try to strip the same number of right parens from url // as there are left parens. Here, lParenCounter must be // a RegExp object. You cannot use a literal // while (/\(/g.exec(lParens)) { ... } // because an object is needed to store the lastIndex state. var lParenCounter = /\(/g; while (lParenCounter.exec(lParens)) { var m; // We want m[1] to be greedy, unless a period precedes the // right parenthesis. These tests cannot be simplified as // /(.*)(\.?\).*)/.exec(url) // because if (.*) is greedy then \.? never gets a chance. if (m = /(.*)(\.\).*)/.exec(url) || /(.*)(\).*)/.exec(url)) { url = m[1]; rParens = m[2] + rParens; } } return lParens + "<a href='" + url + "'>" + url + "</a>" + rParens; }); } 

用HTML链接replace文本中的url,忽略href / pre标签中的url。 https://github.com/JimLiu/auto-link

我已经写了另一个JavaScript库,它可能会更好,因为它是非常敏感的,尽可能less的误报,快速和小型的。 我目前正在积极维护它,所以请在演示页面进行testing,看看它是如何工作的。

链接: https : //github.com/alexcorvi/anchorme.js