JavaScript模仿QQ微博中自动识别网址,将其转换为超链接,以“网页链接”的形式展现,可以点击直接打开。
需求:
项目中在做分享动态时要做一个支持分享网址链接直接点击打开的功能。
方案原型:
将输入的完整网址,在发表动态后,显示时,将原网址链接转换为超链接。
要求:
必须为完整网址,如:
http://baidu.com;https://baidu.com;https://yq.aliyun.com/articles/163180?spm=5176.blogshare163180.0.0.0sZT1B
网址不完整不能直接打开,如:
baidu.com;yq.aliyun.com/articles/163180?spm=5176.blogshare163180.0.0.0sZT1B
扩展:
展示动态时,自动抓取网址链接网页的标题,抓取到后超链接 显示对应的标题,而不是 “网页链接”,若抓取不到,默认显示 “网页链接”。
边界问题:
识别网址时正确区分网址和非网址链接的文字,根据要求我们必须要求网址以 http:// 或者https:// 开头,但网址结尾部分与文字的区分识别有些难度,主要是以下几点:
中文域名的网址, 如: .中国 .公司 .网络网址中有中文, 如: http://52debug.net/pub/#g=1&p=推荐-所有成果网址参数是否正确结束,如:给大家推荐一篇文章,http://52debug.net/pub/#g=1&p=推荐-所有成果 这篇文章真的很精彩!超长网址的处理,如: https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&tn=monline_4_dg&wd=.中国&oq=%E5%8F%91%E5%8A%A8%E6%80%81%E5%A6%82%E4%BD%95%E5%8C%BA%E5%88%86%E7%BD%91%E5%9D%80%E5%92%8C%E5%85%B6%E4%BB%96%E6%96%87%E5%AD%97&rsv_pq=b732ea4400005764&rsv_t=b9c1Jn2RVdEK2W5qgmMmQIrGZA1GCyzAYAHZjZemjrte2U9CwZWdJK1ongeVhpfZHINH&rqlang=cn&rsv_enter=1&inputT=9291&rsv_sug3=110&rsv_sug1=77&rsv_sug7=101&bs=发动态如何区分网址和其他文字
网址识别分析:
关于网址的识别,按最长串匹配的原则,可以构造一个有穷状态自动机,用于识别网址。
匹配 http://|https:// ,匹配成功执行 2,否则 9匹配 **.(合法域名后缀),匹配成功执行 3, 否则 9匹配 请求路径 (/*){0,n},匹配成功执行 4,否则 7匹配 参数起始标识 ?(&)?,匹配成功执行 5,否则 7匹配 请求参数 (.)=(.),匹配成功执行 6, 否则 7匹配 参数分隔符 &,匹配成功执行 5, 否则 7匹配 网址与非网址部分的文字间隔识别符,可以是 中英文逗号,分号,空格,回车等,匹配成功则 8,否则 9成功匹配出网址,将其展示为超链接。识别网址失败,不能识别的网址。
上面这个识别规则是比较严谨些的规则,可以防止http://sfadsfsd 这样类似的假链接。但考虑的可能也并不是很全面,实现起来稍微有些复杂。参考了下QQ对于网址的识别过滤规则,试了下,QQ并没有像上述过程一样去严格识别网址,也没有去支持识别中文域名或者网址参数为中文的情况,而仅仅是识别出http:// 之后,遇到空格回车等空白字符或者中文字符后就取从http:// 到空白或中文的内容作为网址,转换为链接。而项目中确实不用考虑的太复杂,因此本着简单实现的想法,就采用了以下简化的识别规则:
匹配 http://|https:// ,匹配成功执行 2,否则 4匹配任意ASCII码表中非空白字符, 直到匹配到 空格,回车,换行符,制表符等空白字符或者非ASCII码字符(如中文等),成功则3,否则 4成功匹配出网址,将其展示为超链接。识别网址失败,不能识别的网址。
具体实现见代码部分。
关于代码:
新建js文件粘贴该代码。在页面中引入该js,即可通过js调用var newstr = transUrl(str);来获取转换后的内容字符串。
;(function(window, document) {
var matchUrl = function(str) {
var Match = function(str, index, lastIndex) {
this.str = str; //匹配到的url
this.index = index; //匹配到的字符串在原字符串中的起始位置
this.lastIndex = lastIndex; //匹配到的字符串在原字符串中的终止位置
};
/**
* 匹配http://|https://
*/
var regexp1 = new RegExp('(http:\/\/|https:\/\/)', 'g');
var matchArray = new Array();
var matchStr;
while ((matchStr = regexp1.exec(str)) != null) {
matchArray.push(new Match(matchStr[0], matchStr.index, regexp1.lastIndex));
/*console.log(match)
console.log(regexp1.lastIndex - match.index)*/
}
/**
* 匹配网址分隔符,空白字符或非单字节字符及特殊标点符号,;`·"|'做分隔
*/
var regexp2 = /\s|[^\u0000-\u00FF]|[,;`·"|']/g;
for (var i = 0; i < matchArray.length; i++) {
//考虑内容结束但没有分隔符的情况
var endIndex = matchArray[i + 1] ? matchArray[i + 1].index : str.length;
var substr = str.substring(matchArray[i].lastIndex, endIndex);
if ((matchStr = regexp2.exec(substr)) != null) { //匹配到分隔符
if (regexp2.lastIndex > 1) { //提取网址
matchArray[i].lastIndex += regexp2.lastIndex - 1;
matchArray[i].str = str.substring(matchArray[i].index, matchArray[i].lastIndex);
} else { //考虑"http:// "这样的情况
matchArray.splice(i, 1);
}
} else if (endIndex == str.length) { //考虑内容末尾无空白符的情况
if (matchArray[i].lastIndex < endIndex) { //提取网址
matchArray[i].lastIndex = endIndex;
matchArray[i].str = str.substring(matchArray[i].index, endIndex);
} else { //考虑内容末尾无空白符,但也没有实际网址的情况,如:"http://"
matchArray.splice(i, 1);
}
} //考虑内容并未到结尾,无空白符的情况,如:http://baidu.comhttp://sina.com,这种情况识别为一个网址
else if (matchArray[i + 1] && (endIndex == matchArray[i + 1].index)) {
matchArray.splice(i + 1, 1);
i = i - 1;
} else { //其他情况
matchArray.splice(i, 1);
}
//console.log(matchStr);
regexp2.lastIndex = 0;
}
return matchArray;
}
var transUrl = function(str) {
var matchArray = matchUrl(str);
var newstr = "";
for(var i=0; i <= matchArray.length; i++){
var beginIndex = i==0 ? 0 : matchArray[i-1].lastIndex;
var endIndex = i == matchArray.length ? str.length : matchArray[i].index;
var stri = str.substring(beginIndex, endIndex);
var urli = "";
if(i < matchArray.length){
urli = " <a href=\"" + matchArray[i].str + "\" style=\"color: #005eac !important;\" target=\"_blank\">网页链接</a> ";
}
newstr += stri + urli;
}
//console.log(newstr)
return newstr;
}
window.transUrl = transUrl;
}(window, document));
相关资源:JavaScript-源码