我使用下面的函数来匹配给定文本中的URL并替换它们用于HTML链接.正则表达式工作得很好,但目前我只是替换了第一场比赛.
我如何替换所有的URL?我想我应该使用exec命令,但我并没有真正想到如何做到这一点.
function replaceURLWithHTMLLinks(text) { var exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/i; return text.replace(exp,"$1"); }
Dan Dascales.. 336
首先,滚动自己的正则表达式来解析URL是一个糟糕的主意.根据RFC,你必须想象这是一个常见的问题,有人为它编写,调试和测试了一个库.URI很复杂 - 请查看Node.js中的URL解析代码和URI方案的Wikipedia页面.
在解析URL方面有很多边缘案例:国际域名,实际(.museum
)与不存在(.etc
)TLD,包括括号的奇怪标点符号,URL末尾的标点符号,IPV6主机名等.
我已经看了一吨的图书馆,并有几个值得使用,尽管一些缺点:
Soapbox的linkify已经看到了一些认真的努力,并且2015年6月的一个主要重构 删除了jQuery依赖.它仍然存在IDN问题.
AnchorMe是一个声称更快,更精简的新手.一些IDN问题也是如此.
Autolinker.js非常具体地列出了功能(例如"将正确处理HTML输入.该实用程序不会更改href
anchor()标记内的属性").当演示可用时,我会对它进行一些测试.
我已经快速取消了这项任务资格的图书馆:
Django的urlize 没有正确处理某些TLD(这是有效TLD的官方列表.没有演示.
如果没有http://,autolink-js将无法检测到"www.google.com",因此它不太适合自动链接纯文本中的"临时URL"(没有方案/协议).
Ben Alman的linkify自2009年以来一直没有得到维护.
如果你坚持使用正则表达式,那么最全面的是来自Component的URL regexp,尽管它会通过查看错误地检测到一些不存在的双字母TLD.
首先,滚动自己的正则表达式来解析URL是一个糟糕的主意.根据RFC,你必须想象这是一个常见的问题,有人为它编写,调试和测试了一个库.URI很复杂 - 请查看Node.js中的URL解析代码和URI方案的Wikipedia页面.
在解析URL方面有很多边缘案例:国际域名,实际(.museum
)与不存在(.etc
)TLD,包括括号的奇怪标点符号,URL末尾的标点符号,IPV6主机名等.
我已经看了一吨的图书馆,并有几个值得使用,尽管一些缺点:
Soapbox的linkify已经看到了一些认真的努力,并且2015年6月的一个主要重构 删除了jQuery依赖.它仍然存在IDN问题.
AnchorMe是一个声称更快,更精简的新手.一些IDN问题也是如此.
Autolinker.js非常具体地列出了功能(例如"将正确处理HTML输入.该实用程序不会更改href
anchor()标记内的属性").当演示可用时,我会对它进行一些测试.
我已经快速取消了这项任务资格的图书馆:
Django的urlize 没有正确处理某些TLD(这是有效TLD的官方列表.没有演示.
如果没有http://,autolink-js将无法检测到"www.google.com",因此它不太适合自动链接纯文本中的"临时URL"(没有方案/协议).
Ben Alman的linkify自2009年以来一直没有得到维护.
如果你坚持使用正则表达式,那么最全面的是来自Component的URL regexp,尽管它会通过查看错误地检测到一些不存在的双字母TLD.
问题中的正则表达式错过了很多边缘情况.在检测URL时,最好使用专门的库来处理国际域名,新的顶级域名(如TLD).museum
,括号和URL末尾的其他标点符号以及许多其他边缘情况.有关其他一些问题的解释,请参阅Jeff Atwood的博客文章The URL with URL.
URL匹配库的最佳摘要在Dan Dascalescu的答案中
(截至2014年2月)
在正则表达式的末尾添加"g"以启用全局匹配:
/ig;
但这只能解决正则表达式只替换第一个匹配的问题.不要使用该代码.
我对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, '$1'); //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$2'); //Change email addresses to mailto:: links. replacePattern3 = /(([a-zA-Z0-9\-\_\.])+@[a-zA-Z\_]+?(\.[a-zA-Z]{2,6})+)/gim; replacedText = replacedText.replace(replacePattern3, '$1'); return replacedText; }
对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, '$&') .replace(pseudoUrlPattern, '$1$2') .replace(emailAddressPattern, '$&'); }; }
谢谢,这非常有帮助.我还想要一些可以链接看似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, '$1'); //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$2'); //Change email addresses to mailto:: links var replacePattern3 = /(\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,6})/gim; var replacedText = replacedText.replace(replacePattern3, '$1'); return replacedText }
在第二次替换中,(^ | [^ /])部分仅替换www.whatever.com,如果它还没有前缀为// - 以避免在第一次替换中已经链接了URL时进行双重链接.此外,www.whatever.com可能位于字符串的开头,这是正则表达式中该部分的第一个"或"条件.
这可以作为jQuery插件集成,如上面所示的Jesse P - 但我特别想要一个不在现有DOM元素上运行的常规函数,因为我正在使用我拥有的文本然后将它添加到DOM中,我希望在添加文本之前将文本"链接",因此我将文本传递给此函数.效果很好.
识别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.', {nofollow: true, autoescape: true}) => "Go to SO (stackoverflow.com) and ask. <grin>"
第二个参数,如果为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, '$&') .replace(pseudoUrlPattern, '$1$2') .replace(emailAddressPattern, '$1'); }; }
我在谷歌搜索了更新的东西并遇到了这个:
$('p').each(function(){ $(this).html( $(this).html().replace(/((http|https|ftp):\/\/[\w?=&.\/-;#~%-]+(?![\w\s?&.\/;#~%"=-]*>))/g, '$1 ') ); });
演示: http ://jsfiddle.net/kachibito/hEgvc/1/
适用于普通链接.
最好的脚本:http: //benalman.com/projects/javascript-linkify-process-lin/
此解决方案与许多其他解决方案一样,并且实际上使用与其中一个相同的正则表达式,但是它不会返回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; }
有一些警告,即旧的IE和textContent支持.
这是一个演示.