2012-05-30 17 views
0

我不擅长经常性的exp。 ,我想改变文本用链接替换URL或完全合格的域名

例如

Hello http://stackoverflow.com 
Hello www.stackoverflow.com 

我希望链接的超链接的计算器链接

Hello <a href='http://stackoverflow.com'>http://stackoverflow.com</a> 
Hello <a href='http://www.stackoverflow.com'>www.stackoverflow.com</a> 

我用这个

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

但这仅与http://

预先感谢

+1

如果没有协议,很难弄清楚什么是链接。人们有时会这样写。这是一个链接吗? :) – KillerX

+0

你会努力去匹配“stackoverflow.com”而不会冒险将文本转换为人们并不打算成为的链接。 – crdx

+0

好的我应该怎么做才能像上面提到的那样? – Sedz

回答

6

正如其他人说,首先需要定义什么是“链接”。 (请注意,“链接”仅是此上下文中的“超链接”的缩写,因此您的句子没有意义。)考虑到您的两个示例,您希望匹配Uniform Resource Identifiers (URIs)Fully Qualified Domain Names (FQDNs)

为了做到这一点,你应该采取的正则表达式可以在RFC 3986, Appendix B发现 -

^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))? 

- 它变成一个在单词边界匹配,只接受//后FQDN和可选的端口号,并且停止在空白(\s):

 ,----scheme----. ,-Fully Qualified Domain Name-.,-port.,--path--.,---query----.,fragment 
     |    | |        ||  ||  ||   ||  | 
(^|\s)(([^:/?#\s]+):)?(//([A-Za-z0-9-]+\.)+[A-Za-z0-9-]+(:\d+)?([^?#\s]*)(\?([^#\s]*))?(#(\S*))? 

然后你就可以使方案部分可选 -

      | 
          v 
(^|\s)((([^:/?#\s]+):)?//)?(([A-Za-z0-9-]+\.)+[A-Za-z0-9-]+(:\d+)?([^?#\s]*)(\?([^#\s]*))?(#(\S*))? 

- 写这是一个正则表达式文本(式中斜杠需要进行转义,因为他们作为分隔符):

/(^|\s)((([^:\/?#\s]+):)?\/\/)?(([A-Za-z0-9-]+\.)+[A-Za-z0-9-]+)(:\d+)?([^?#\s]*)(\?([^#\s]*))?(#(\S*))?/ 

(您可能要匹配IDNs过; JSX:regexp.js及其对Unicode字符属性的支持可以帮助您,请参阅How to remove all characters from a string。你可能要预先考虑到FQDN子表达式为用户名的URI,(\[email protected])?可选的和过时传输的子表达式,用于代理访问)。

然后你就可以更换所有字符串(g叶形的修改),其这将匹配相应的a元素:

var rx = /(^|\s)(((([^:\/?#\s]+):)?\/\/)?(([A-Za-z0-9-]+\.)+[A-Za-z0-9-]+)(:\d+)?([^?#\s]*)(\?([^#\s]*))?(#(\S*))?)/g; 

str = str.replace(rx, 
    function (match, optionalWhitespace, uri, scheme, p4, protocol, fqdn, p7, port, 
      path, query, queryVal, fragment, fragId) { 
    return (optionalWhitespace ? optionalWhitespace : '') 
     + '<a href="' + (protocol ? uri : 'http://' + uri) 
     + '" target="_blank">' + uri + '<\/a>'; 
    }); 

必须假定在这里,当你看到的只是一个FQDN前缀,它是一个没有安全网站的域名,并在前面加上http://。否则,href属性中的URI参考将引用您的网站中可能存在的路径,该网站以域名作为其名称(http://your-site.example/other-site.example.com),这可能不是您想要的。

这是可能的,但不太可能,这个表达式匹配你的情况太多;用尽可能多的输入进行测试,并根据需要进行调整。如果向后兼容性不是问题,请使用non-capturing parentheses(?:…))来提高效率和减少命名参数;详情请参阅ECMAScript Support Matrix

捕获FQDN部分 - 围绕([A-Za-z0-9-]+\.)+[A-Za-z0-9-]+的括号是可选的;你可能想用它来给a元素一个class属性值,以特殊的方式对它进行格式化,比如预先添加一个适配图标,例如指向Stack Overflow,Wikipedia,Twitter或Facebook的链接。

您可能还想重新考虑使用target属性(for Strict (X)HTML, you MUST remove it)。用户可能不善于不控制链接目标的打开位置。改为以标题,图标,光标等形式提供提示。

0

使用此代码:

var exp = /(((?:(?:https?|ftp|file):)?\/\/)?(?:[\w-]+\.)?[\w-]+\.\w{2,5}(?:\/[^\s\/]*)*)/ig; 
return str.replace(exp, function(_, link, protocol){ 
    return link.link(protocol ? link : "http://" + link); 
}); 
+0

非常感谢您的回答,但它不起作用 – Sedz

+0

啊,现在我明白了。你的问题是该协议可能被忽略。编辑上面的代码。 – fb55

+0

表达太贪婪;它将匹配任何文本。在哪个“旧浏览器”中你观察过'$&'不可用? – PointedEars