2009-09-30 68 views
94

有没有人有建议检测一组字符串中的URL?使用JavaScript检测文本中的URL

arrayOfStrings.forEach(function(string){ 
    // detect URLs in strings and do something swell, 
    // like creating elements with links. 
}); 

更新:我清盘显然,数年后使用这个正则表达式链路检测...。

kLINK_DETECTION_REGEX = /(([a-z]+:\/\/)?(([a-z0-9\-]+\.)+([a-z]{2}|aero|arpa|biz|com|coop|edu|gov|info|int|jobs|mil|museum|name|nato|net|org|pro|travel|local|internal))(:[0-9]{1,5})?(\/[a-z0-9_\-\.~]+)*(\/([a-z0-9_\-\.]*)(\?[a-z0-9+_\-\.%=&]*)?)?(#[a-zA-Z0-9!$&'()*+.=-_~:@/?]*)?)(\s+|$)/gi 

完整的帮手(可选​​Handlebars支持)在gist #1654670

+7

它可能不是一个好主意,尝试列出的有限集合顶级域名,因为他们不断创建新的域名。 – 2013-04-11 13:47:43

+0

同意。有时我们需要的是具有顶级域名(TLD)的可更新代码。实际上可以构建脚本以将TLD附加到代码中的正则表达式或动态代码更新TLD中。生活中有些东西意味着像TLD和时区一样标准化。有限控制可能很适合验证真实世界地址用例的现有“TLD”可验证URL。 – 2017-09-28 07:36:31

回答

135

首先你需要一个好的正则表达式来匹配url。这很难做到。见hereherehere

......几乎所有的东西是一个有效的URL。有 是 拆分它的一些标点规则。如果没有任何 标点符号,您仍然有一个有效的 网址。

仔细检查RFC,看看您的 是否可以构建“无效”URL。 规则非常灵活。

例如:::::是一个有效的URL。 路径是":::::"。一个漂亮的 愚蠢的文件名,但一个有效的文件名。

另外,/////是有效的URL。网址(“主机名”)的 是""。路径 是"///"。再次,愚蠢。另外 有效。该URL标准化为"///" 这是等效的。

类似"bad://///worse/////" 是完全有效的。愚蠢但有效。

无论如何,这个答案并不意味着给你最好的正则表达式,而是给出你如何使用JavaScript在文本中进行字符串换行的证明。

行,所以让刚刚使用这一个:/(https?:\/\/[^\s]+)/g

再次,这是一个糟糕的正则表达式。它会有很多误报。然而这个例子足够好。

function urlify(text) { 
    var urlRegex = /(https?:\/\/[^\s]+)/g; 
    return text.replace(urlRegex, function(url) { 
     return '<a href="' + url + '">' + url + '</a>'; 
    }) 
    // or alternatively 
    // return text.replace(urlRegex, '<a href="$1">$1</a>') 
} 

var text = "Find me at http://www.example.com and also at http://stackoverflow.com"; 
var html = urlify(text); 

// html now looks like: 
// "Find me at <a href="http://www.example.com">http://www.example.com</a> and also at <a href="http://stackoverflow.com">http://stackoverflow.com</a>" 

所以在和尝试:

$$('#pad dl dd').each(function(element) { 
    element.innerHTML = urlify(element.innerHTML); 
}); 
+0

酷 - 正是我所期待的。 RexExp的一直超越我。 – arbales 2009-10-03 08:03:14

+2

“许多误报”的一些例子将大大改善这个答案。否则,未来的Google员工只剩下一些(也许是有效的)FUD。 – cmcculloh 2014-07-23 02:41:59

+0

我从来不知道你可以传递函数作为'''.replace'''的第二个参数: – 2015-06-17 15:44:45

84

这里是我结束了使用作为我正则表达式:

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

这不包括在URL后标点符号。新月的功能就像一个魅力:) 这样:

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

最后一个真正在最明显的情况下工作的正则表达式!这一个值得一个书签。我测试了数千个来自Google搜索的例子,直到我找到它。 – Ismael 2015-01-16 15:11:18

+2

简单而好看! 但是'urlRegex'应该被定义为_outside_'linkify',因为编译它很昂贵。 – 2017-08-19 19:22:52

+0

这无法检测到完整的URL:http://disney.wikia.com/wiki/Pua_(Moana) – Jry9972 2017-12-14 11:07:29

5

功能,能够进一步提高来渲染图像,以及:

function renderHTML(text) { 
    var rawText = strip(text) 
    var urlRegex =/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig; 

    return rawText.replace(urlRegex, function(url) { 

    if ((url.indexOf(".jpg") > 0) || (url.indexOf(".png") > 0) || (url.indexOf(".gif") > 0)) { 
      return '<img src="' + url + '">' + '<br/>' 
     } else { 
      return '<a href="' + url + '">' + url + '</a>' + '<br/>' 
     } 
    }) 
} 

或链接到fiull尺寸图像的缩略图:

return '<a href="' + url + '"><img style="width: 100px; border: 0px; -moz-border-radius: 5px; border-radius: 5px;" src="' + url + '">' + '</a>' + '<br/>' 

这里是strip()函数,通过删除任何现有的html来预处理文本字符串以实现统一性。

function strip(html) 
    { 
     var tmp = document.createElement("DIV"); 
     tmp.innerHTML = html; 
     var urlRegex =/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig; 
     return tmp.innerText.replace(urlRegex, function(url) {  
     return '\n' + url 
    }) 
} 
+0

发帖时www.google.com,它没有检测 – 2016-10-21 10:53:40

35

我用Google搜索这个问题相当长一段时间,那么它发生,我认为有一个Android方法,android.text.util.Linkify,利用一些相当强劲的正则表达式来做到这一点。幸运的是,Android是开源的。

他们使用几种不同的模式来匹配不同类型的网址。你可以在这里找到他们: http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.0_r1/android/text/util/Regex.java#Regex.0WEB_URL_PATTERN

如果你只是关心匹配WEB_URL_PATTERN该URL的,也就是说,符合RFC 1738规范的网址,您可以使用此:

/((?:(http|https|Http|Https|rtsp|Rtsp):\/\/(?:(?:[a-zA-Z0-9\$\-\_\.\+\!\*\'\(\)\,\;\?\&\=]|(?:\%[a-fA-F0-9]{2})){1,64}(?:\:(?:[a-zA-Z0-9\$\-\_\.\+\!\*\'\(\)\,\;\?\&\=]|(?:\%[a-fA-F0-9]{2})){1,25})?\@)?)?((?:(?:[a-zA-Z0-9][a-zA-Z0-9\-]{0,64}\.)+(?:(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])|(?:biz|b[abdefghijmnorstvwyz])|(?:cat|com|coop|c[acdfghiklmnoruvxyz])|d[ejkmoz]|(?:edu|e[cegrstu])|f[ijkmor]|(?:gov|g[abdefghilmnpqrstuwy])|h[kmnrtu]|(?:info|int|i[delmnoqrst])|(?:jobs|j[emop])|k[eghimnrwyz]|l[abcikrstuvy]|(?:mil|mobi|museum|m[acdghklmnopqrstuvwxyz])|(?:name|net|n[acefgilopruz])|(?:org|om)|(?:pro|p[aefghklmnrstwy])|qa|r[eouw]|s[abcdeghijklmnortuvyz]|(?:tel|travel|t[cdfghjklmnoprtvwz])|u[agkmsyz]|v[aceginu]|w[fs]|y[etu]|z[amw]))|(?:(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[0-9])))(?:\:\d{1,5})?)(\/(?:(?:[a-zA-Z0-9\;\/\?\:\@\&\=\#\~\-\.\+\!\*\'\(\)\,\_])|(?:\%[a-fA-F0-9]{2}))*)?(?:\b|$)/gi; 

这里是源全文:

"((?:(http|https|Http|Https|rtsp|Rtsp):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)" 
+ "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_" 
+ "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?" 
+ "((?:(?:[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}\\.)+" // named host 
+ "(?:" // plus top level domain 
+ "(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])" 
+ "|(?:biz|b[abdefghijmnorstvwyz])" 
+ "|(?:cat|com|coop|c[acdfghiklmnoruvxyz])" 
+ "|d[ejkmoz]" 
+ "|(?:edu|e[cegrstu])" 
+ "|f[ijkmor]" 
+ "|(?:gov|g[abdefghilmnpqrstuwy])" 
+ "|h[kmnrtu]" 
+ "|(?:info|int|i[delmnoqrst])" 
+ "|(?:jobs|j[emop])" 
+ "|k[eghimnrwyz]" 
+ "|l[abcikrstuvy]" 
+ "|(?:mil|mobi|museum|m[acdghklmnopqrstuvwxyz])" 
+ "|(?:name|net|n[acefgilopruz])" 
+ "|(?:org|om)" 
+ "|(?:pro|p[aefghklmnrstwy])" 
+ "|qa" 
+ "|r[eouw]" 
+ "|s[abcdeghijklmnortuvyz]" 
+ "|(?:tel|travel|t[cdfghjklmnoprtvwz])" 
+ "|u[agkmsyz]" 
+ "|v[aceginu]" 
+ "|w[fs]" 
+ "|y[etu]" 
+ "|z[amw]))" 
+ "|(?:(?:25[0-5]|2[0-4]" // or ip address 
+ "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(?:25[0-5]|2[0-4][0-9]" 
+ "|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1]" 
+ "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}" 
+ "|[1-9][0-9]|[0-9])))" 
+ "(?:\\:\\d{1,5})?)" // plus option port number 
+ "(\\/(?:(?:[a-zA-Z0-9\\;\\/\\?\\:\\@\\&\\=\\#\\~" // plus option query params 
+ "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?" 
+ "(?:\\b|$)"; 

如果你想成为真正看中的,你可以测试电子邮件地址为好。电子邮件地址的正则表达式是:

/[a-zA-Z0-9\\+\\.\\_\\%\\-]{1,256}\\@[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}(\\.[a-zA-Z0-9][a-zA-Z0-9\\-]{0,25})+/gi 

PS:用上述正则表达式支持的顶级域名是当前为2007年6月的对于最新的列表中,您需要检查https://data.iana.org/TLD/tlds-alpha-by-domain.txt

+1

既然你有一个不区分大小写的正则表达式,你不必指定'a-zA-Z'和'http | https | Http | https | rtsp | Rtsp'。 – Ryan 2013-12-05 03:06:54

+0

RFC 1738与链接不匹配http://t.co/500S3LZpWA – Ismael 2015-01-16 12:55:16

+2

这很好,但我不确定我会不会使用它。对于大多数使用情况,我宁愿接受一些误报,而不愿意使用依赖于硬编码顶级域名列表的方法。如果您在代码中列出了顶级域名(TLD),那么您可以保证它将在某一天过时,并且如果我可以避免,我宁愿不在日后的代码中构建强制性未来维护。 – 2015-03-29 11:10:23

1

tmp.innerText未定义。您应该使用tmp.innerHTML

function strip(html) 
    { 
     var tmp = document.createElement("DIV"); 
     tmp.innerHTML = html; 
     var urlRegex =/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig; 
     return tmp.innerHTML .replace(urlRegex, function(url) {  
     return '\n' + url 
    }) 
14

基于新月新鲜答案

如果要检测环节 以http

://不包含http://和WWW。您可以使用下面的

function urlify(text) { 
    var urlRegex = /(((https?:\/\/)|(www\.))[^\s]+)/g; 
    //var urlRegex = /(https?:\/\/[^\s]+)/g; 
    return text.replace(urlRegex, function(url,b,c) { 
     var url2 = (c == 'www.') ? 'http://' +url : url; 
     return '<a href="' +url2+ '" target="_blank">' + url + '</a>'; 
    }) 
} 
2

该库在NPM看起来是非常全面的https://www.npmjs.com/package/linkifyjs

Linkify是一个小而全面的JavaScript插件以纯文本查找网址,并将其转换为HTML链接。它适用于所有有效的URL和电子邮件地址。

+0

我刚刚完成在我的项目中实现linkifyjs,这太棒了。 Linkifyjs应该是这个问题的答案。另一个要看的是https://github.com/twitter/twitter-text – 2017-06-01 20:08:01

0

试试这个:

function isUrl(s) { 
    if (!isUrl.rx_url) { 
     // taken from https://gist.github.com/dperini/729294 
     isUrl.rx_url=/^(?:(?:https?|ftp):\/\/)?(?:\S+(?::\S*)[email protected])?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,}))\.?)(?::\d{2,5})?(?:[/?#]\S*)?$/i; 
     // valid prefixes 
     isUrl.prefixes=['http:\/\/', 'https:\/\/', 'ftp:\/\/', 'www.']; 
     // taken from https://w3techs.com/technologies/overview/top_level_domain/all 
     isUrl.domains=['com','ru','net','org','de','jp','uk','br','pl','in','it','fr','au','info','nl','ir','cn','es','cz','kr','ua','ca','eu','biz','za','gr','co','ro','se','tw','mx','vn','tr','ch','hu','at','be','dk','tv','me','ar','no','us','sk','xyz','fi','id','cl','by','nz','il','ie','pt','kz','io','my','lt','hk','cc','sg','edu','pk','su','bg','th','top','lv','hr','pe','club','rs','ae','az','si','ph','pro','ng','tk','ee','asia','mobi']; 
    } 

    if (!isUrl.rx_url.test(s)) return false; 
    for (let i=0; i<isUrl.prefixes.length; i++) if (s.startsWith(isUrl.prefixes[i])) return true; 
    for (let i=0; i<isUrl.domains.length; i++) if (s.endsWith('.'+isUrl.domains[i]) || s.includes('.'+isUrl.domains[i]+'\/') ||s.includes('.'+isUrl.domains[i]+'?')) return true; 
    return false; 
} 

function isEmail(s) { 
    if (!isEmail.rx_email) { 
     // taken from http://stackoverflow.com/a/16016476/460084 
     var sQtext = '[^\\x0d\\x22\\x5c\\x80-\\xff]'; 
     var sDtext = '[^\\x0d\\x5b-\\x5d\\x80-\\xff]'; 
     var sAtom = '[^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+'; 
     var sQuotedPair = '\\x5c[\\x00-\\x7f]'; 
     var sDomainLiteral = '\\x5b(' + sDtext + '|' + sQuotedPair + ')*\\x5d'; 
     var sQuotedString = '\\x22(' + sQtext + '|' + sQuotedPair + ')*\\x22'; 
     var sDomain_ref = sAtom; 
     var sSubDomain = '(' + sDomain_ref + '|' + sDomainLiteral + ')'; 
     var sWord = '(' + sAtom + '|' + sQuotedString + ')'; 
     var sDomain = sSubDomain + '(\\x2e' + sSubDomain + ')*'; 
     var sLocalPart = sWord + '(\\x2e' + sWord + ')*'; 
     var sAddrSpec = sLocalPart + '\\x40' + sDomain; // complete RFC822 email address spec 
     var sValidEmail = '^' + sAddrSpec + '$'; // as whole string 

     isEmail.rx_email = new RegExp(sValidEmail); 
    } 

    return isEmail.rx_email.test(s); 
} 

还将认识的网址,如google.comhttp://www.google.blahttp://google.blawww.google.bla但不google.bla