Answers:
首先,滚动自己的regexp来解析URL是一个糟糕的主意。您必须想象这是一个很常见的问题,根据RFC,有人为此编写,调试和测试了一个库。URI很复杂 -请在Node.js和URI方案的Wikipedia页面上查看用于URL解析的代码。
解析URL时有很多边缘情况:国际域名,实际(.museum
)与不存在(.etc
)TLD,包含括号的怪异标点,URL末尾的标点,IPV6主机名等。
href
anchor()标记内的属性”)。演示可用时我会对其进行一些测试。我已迅速被取消此任务资格的图书馆:
如果您坚持使用正则表达式,那么最全面的是Component的URL regexp,尽管它会通过查看错误地检测出一些不存在的两个字母的TLD。
问题中的正则表达式遗漏了很多极端情况。检测URL时,最好使用专门的库来处理国际域名,.museum
URL内和末尾的新TLD(例如,括号和其他标点符号)以及许多其他情况。有关其他一些问题的说明,请参见Jeff Atwood的博客文章“ 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, '<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;
}
[a-zA-Z]{2,6}
应该阅读一些类似的内容(?:[a-zA-Z]{2,6})+
以匹配更复杂的域名,例如email@example.co.uk。
http://
或没有URL www
呢?这对这类网址有用吗?
replacePattern3 = /(\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,6})/gim;
使用此行replacePattern3 = /(\w+@[a-zA-Z_]+?(\.[a-zA-Z]{2,6})+)/gim;
可解决mailto问题:)
对Linkify()
上面的Travis 代码进行了一些优化。我还修复了一个错误,该错误导致子域类型格式的电子邮件地址不匹配(即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>');
};
}
+
用于电子邮件用户名(例如)foo+bar@domain.com
。我用电子邮件模式修复了它/[\w.+]+@[a-zA-Z_-]+?(?:\.[a-zA-Z]{2,6})+/gim
(请注意+
第一个括号中的),但是我不知道这是否会破坏其他功能。
谢谢,这非常有帮助。我还希望可以链接看起来像URL的东西-作为基本要求,即使没有http://协议前缀,它也可以链接www.yahoo.com之类的东西。所以基本上,如果是“ www” 存在,它将链接它并假定它是http://。我还希望电子邮件变成mailto:链接。示例: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
}
在第二次替换中,(^ | [^ /])部分仅在未以//开头的情况下替换www.whatever.com,以防止双重链接(如果在第一次替换中已经链接了URL)。另外,www.whatever.com可能位于字符串的开头,这是正则表达式中该部分的第一个“或”条件。
可以将其集成为jQuery插件(如上面的Jesse P所示),但是我特别希望一个不对现有DOM元素起作用的常规函数,因为我要获取已有的文本,然后将其添加到DOM中,在添加文本之前,我希望文本被“链接化”,因此我通过此函数传递文本。效果很好。
标识URL十分棘手,因为它们经常被标点符号包围,并且用户经常不使用完整的URL形式。存在许多用超链接替换URL的JavaScript函数,但是我找不到urlize
在基于Python的Web框架Django中与过滤器一样工作的函数。因此,我将Django的urlize
功能移植到了JavaScript:
一个例子:
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. <grin>"
第二个参数(如果为true)将导致rel="nofollow"
插入。第三个参数(如果为true)将转义在HTML中具有特殊含义的字符。请参阅README文件。
django_compatible
为false,它将更好地处理该用例。
我将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>');
};
}
我在Google上搜索了任何更新的内容,然后遇到了这个问题:
$('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/
对于普通链接确实很好用。
http://example.com/folder/folder/folder/
或其他格式的任何内容https://example.org/blah
-只是您可以匹配95-99%用例的典型非疯狂URL格式。我将其用于内部管理区域,因此不需要任何花哨的功能即可捕获边缘情况或哈希链接。
最好的脚本来做到这一点: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支持。
这是一个演示。
如果您需要显示较短的链接(仅域),但具有相同的长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>");
}
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>");
}
以下是一些经过测试的字符串:
注意:如果您不想通过www
有效的密码,只需在reg ex下方使用:
/(\b((https?|ftp|file):\/\/|(www))[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/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/>(");
}
把事情简单化!说你不能拥有的,而不是你可以拥有的:)
如上所述,URL可能非常复杂,尤其是在“?”之后,并且并非所有URL都以“ www”开头。例如maps.bing.com/something?key=!"£$%^*()&lat=65&lon&lon=20
因此,与其拥有一个复杂的正则表达式,使其不能满足所有极端情况,并且将难以维护,不如这么简单的正则表达式在实践中对我来说很好。
比赛
http(s):// (anything but a space)+
www. (anything but a space)+
“一切” [^'"<>\s]
...基本上是贪婪的匹配,继续出现一个空格,引号,尖括号或行尾
也:
请记住要检查它是否不是URL格式,例如文本包含href="..."
或src="..."
添加ref = nofollow(如果适用)
该解决方案不如上面提到的库“好”,但是简单得多,并且在实践中效果很好。
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;
具有国际域名和星体字符支持的正确URL检测不是一件容易的事。linkify-it
库根据许多条件构建正则表达式,最终大小约为6 KB :)。它比当前接受的答案中引用的所有库更准确。
请参阅linkify-it演示以检查所有边缘情况并测试您的情况。
如果需要链接HTML源,则应首先对其进行解析,然后分别迭代每个文本标记。
我已经写了另一个JavaScript库,它对您可能会更好,因为它非常敏感,并且误报率极低,而且体积小巧。我目前正在积极维护它,因此请在演示页面上对其进行测试,并查看它如何为您工作。
我不得不做相反的事情,并且使HTML链接仅进入URL,但是我修改了您的正则表达式,它的工作原理很吸引人,谢谢:)
var exp = /<a\s.*href=['"](\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_ |!:,。;]] [[-A-Z0-9 +&@#\ /%=〜_ |])['“]。*>。* <\ / a> / ig; source = source.replace(exp,“ $ 1”);
Travitron上面的答案中的电子邮件检测对我而言不起作用,因此我用以下代码(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 ”。
从多个来源输入后,我现在有了一个很好的解决方案。它与编写自己的替换代码有关。
回答。
小提琴。
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链接替换文本中的URL,忽略href / pre标签中的URL。 https://github.com/JimLiu/auto-link
这是我的解决方案:
var content = "Visit https://wwww.google.com or watch this video: https://www.youtube.com/watch?v=0T4DQYgsazo and news at http://www.bbc.com";
content = replaceUrlsWithLinks(content, "http://");
content = replaceUrlsWithLinks(content, "https://");
function replaceUrlsWithLinks(content, protocol) {
var startPos = 0;
var s = 0;
while (s < content.length) {
startPos = content.indexOf(protocol, s);
if (startPos < 0)
return content;
let endPos = content.indexOf(" ", startPos + 1);
if (endPos < 0)
endPos = content.length;
let url = content.substr(startPos, endPos - startPos);
if (url.endsWith(".") || url.endsWith("?") || url.endsWith(",")) {
url = url.substr(0, url.length - 1);
endPos--;
}
if (ROOTNS.utils.stringsHelper.validUrl(url)) {
let link = "<a href='" + url + "'>" + url + "</a>";
content = content.substr(0, startPos) + link + content.substr(endPos);
s = startPos + link.length;
} else {
s = endPos + 1;
}
}
return content;
}
function validUrl(url) {
try {
new URL(url);
return true;
} catch (e) {
return false;
}
}
尝试以下功能:
function anchorify(text){
var exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
var text1=text.replace(exp, "<a href='$1'>$1</a>");
var exp2 =/(^|[^\/])(www\.[\S]+(\b|$))/gim;
return text1.replace(exp2, '$1<a target="_blank" href="http://$2">$2</a>');
}
alert(anchorify("Hola amigo! https://www.sharda.ac.in/academics/"));
尝试以下解决方案
function replaceLinkClickableLink(url = '') {
let pattern = new RegExp('^(https?:\\/\\/)?'+
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.?)+[a-z]{2,}|'+
'((\\d{1,3}\\.){3}\\d{1,3}))'+
'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+
'(\\?[;&a-z\\d%_.~+=-]*)?'+
'(\\#[-a-z\\d_]*)?$','i');
let isUrl = pattern.test(url);
if (isUrl) {
return `<a href="${url}" target="_blank">${url}</a>`;
}
return url;
}
URL regexp from Component
是没有发表评论,对其所作的一些解释会有所帮助。Autolinker.js
评论得很好,并经过测试。尽管没有测试,但urlize.js
在Vebjorn Ljosa的答案中链接到的库 看起来也很有特色且维护良好。