先进的HTML字符串替换功能
OP的注释,因为他请求了这样的功能:更改base_url
为代理的base URL,以实现所需的结果。
下面将显示两个功能(代码中包含使用指南)。确保您不跳过此答案的任何部分以完全理解该功能的行为。
rel_to_abs(urL)
-此函数返回绝对URL。当传递具有普遍信任协议的绝对URL时,它将立即返回此URL。否则,将根据base_url
和函数参数生成一个绝对URL 。相对URL正确解析(../
;./
;.
;//
)。replace_all_rel_by_abs
-此函数将解析 所有 出现的在HTML中具有重要意义的URL,例如CSSurl()
,链接和外部资源。请参阅代码以获取已解析实例的完整列表。 以获取经过调整的实现,以 清理 来自外部源(嵌入到文档中)的 HTML字符串 。- 测试用例(在答案的底部):要测试该功能的有效性,只需将小书签粘贴在位置栏上。
rel_to_abs
- 解析相对网址
function rel_to_abs(url){ if(/^(https?|file|ftps?|mailto|javascript|data:image/[^;]{2,9};):/i.test(url)) return url; //Url is already absolute var base_url = location.href.match(/^(.+)/?(?:#.+)?$/)[0]+"/"; if(url.substring(0,2) == "//") return location.protocol + url; else if(url.charAt(0) == "/") return location.protocol + "//" + location.host + url; else if(url.substring(0,2) == "./") url = "." + url; else if(/^s*$/.test(url)) return ""; //Empty = Return nothing else url = "../" + url; url = base_url + url; var i=0 while(//..//.test(url = url.replace(/[^/]+/+..//g,""))); url = url.replace(/.$/,"").replace(//./g,"").replace(/"/g,"%22") .replace(/'/g,"%27").replace(/</g,"%3C").replace(/>/g,"%3E"); return url;}案例/示例:
http://foo.bar
。已经是绝对URL,因此立即返回。/doo
相对于根:返回当前根+提供的相对URL。./meh
相对于当前目录。../booh
相对于父目录。
该函数将相对路径转换为
../,并执行搜索和替换(
http://domain/sub/anything-but-a-slash/../me至
http://domain/sub/me)。
replace_all_rel_by_abs
- 转换
脚本实例内部的 所有相关URL URL(
<script>,事件处理程序 不会
被替换,因为创建一个快速安全的过滤器来解析Javascript几乎是不可能的。
该脚本内部带有一些注释。动态创建正则表达式,因为单个RE的大小可以为 3000个 字符。
<meta http-equiv=refreshcontent=.. >可以以各种方式混淆,因此RE的大小。
function replace_all_rel_by_abs(html){ var att = "[^-a-z0-9:._]"; var entityEnd = "(?:;|(?!\d))"; var ents = {" ":"(?:\s| ?|�*32"+entityEnd+"|�*20"+entityEnd+")", "(":"(?:\(|�*40"+entityEnd+"|�*28"+entityEnd+")", ")":"(?:\)|�*41"+entityEnd+"|�*29"+entityEnd+")", ".":"(?:\.|�*46"+entityEnd+"|�*2e"+entityEnd+")"}; var charMap = {}; var s = ents[" "]+"*"; //Short-hand for common use var any = "(?:[^>"']*(?:"[^"]*"|'[^']*'))*?[^>]*"; function ae(string){ var all_chars_lowercase = string.toLowerCase(); if(ents[string]) return ents[string]; var all_chars_uppercase = string.toUpperCase(); var RE_res = ""; for(var i=0; i<string.length; i++){ var char_lowercase = all_chars_lowercase.charAt(i); if(charMap[char_lowercase]){ RE_res += charMap[char_lowercase]; continue; } var char_uppercase = all_chars_uppercase.charAt(i); var RE_sub = [char_lowercase]; RE_sub.push("�*" + char_lowercase.charCodeAt(0) + entityEnd); RE_sub.push("�*" + char_lowercase.charCodeAt(0).toString(16) + entityEnd); if(char_lowercase != char_uppercase){ RE_sub.push("�*" + char_uppercase.charCodeAt(0) + entityEnd); RE_sub.push("�*" + char_uppercase.charCodeAt(0).toString(16) + entityEnd); } RE_sub = "(?:" + RE_sub.join("|") + ")"; RE_res += (charMap[char_lowercase] = RE_sub); } return(ents[string] = RE_res); } function by(match, group1, group2, group3){ return group1 + rel_to_abs(group2) + group3; } var slashRE = new RegExp(ae("/"), 'g'); var dotRE = new RegExp(ae("."), 'g'); function by2(match, group1, group2, group3){ group2 = group2.replace(slashRE, "/").replace(dotRE, "."); return group1 + rel_to_abs(group2) + group3; } function cr(selector, attribute, marker, delimiter, end){ if(typeof selector == "string") selector = new RegExp(selector, "gi"); attribute = att + attribute; marker = typeof marker == "string" ? marker : "\s*=\s*"; delimiter = typeof delimiter == "string" ? delimiter : ""; end = typeof end == "string" ? "?)("+end : ")("; var re1 = new RegExp('('+attribute+marker+'")([^"'+delimiter+']+'+end+')', 'gi'); var re2 = new RegExp("("+attribute+marker+"')([^'"+delimiter+"]+"+end+")", 'gi'); var re3 = new RegExp('('+attribute+marker+')([^"'][^\s>'+delimiter+']*'+end+')', 'gi'); html = html.replace(selector, function(match){ return match.replace(re1, by).replace(re2, by).replace(re3, by); }); } function cri(selector, attribute, front, flags, delimiter, end){ if(typeof selector == "string") selector = new RegExp(selector, "gi"); attribute = att + attribute; flags = typeof flags == "string" ? flags : "gi"; var re1 = new RegExp('('+attribute+'\s*=\s*")([^"]*)', 'gi'); var re2 = new RegExp("("+attribute+"\s*=\s*')([^']+)", 'gi'); var at1 = new RegExp('('+front+')([^"]+)(")', flags); var at2 = new RegExp("("+front+")([^']+)(')", flags); if(typeof delimiter == "string"){ end = typeof end == "string" ? end : ""; var at3 = new RegExp("("+front+")([^"'][^"+delimiter+"]*" + (end?"?)("+end+")":")()"), flags); var handleAttr = function(match, g1, g2){return g1+g2.replace(at1, by2).replace(at2, by2).replace(at3, by2)}; } else { var handleAttr = function(match, g1, g2){return g1+g2.replace(at1, by2).replace(at2, by2)}; } html = html.replace(selector, function(match){ return match.replace(re1, handleAttr).replace(re2, handleAttr); }); } cri("<meta"+any+att+"http-equiv\s*=\s*(?:""+ae("refresh")+"""+any+">|'"+ae("refresh")+"'"+any+">|"+ae("refresh")+"(?:"+ae(" ")+any+">|>))", "content", ae("url")+s+ae("=")+s, "i"); cr("<"+any+att+"href\s*="+any+">", "href"); cr("<"+any+att+"src\s*="+any+">", "src"); cr("<object"+any+att+"data\s*="+any+">", "data"); cr("<applet"+any+att+"prebase\s*="+any+">", "prebase"); cr("<param"+any+att+"name\s*=\s*(?:""+ae("movie")+"""+any+">|'"+ae("movie")+"'"+any+">|"+ae("movie")+"(?:"+ae(" ")+any+">|>))", "value"); cr(/<style[^>]*>(?:[^"']*(?:"[^"]*"|'[^']*'))*?[^'"]*(?:</style|$)/gi, "url", "\s*\(\s*", "", "\s*\)"); cri("<"+any+att+"style\s*="+any+">", "style", ae("url")+s+ae("(")+s, 0, s+ae(")"), ae(")")); return html;}私有功能的简短摘要:
rel_to_abs(url)
-将相对/未知URL转换为绝对URLreplace_all_rel_by_abs(html)
-用绝对URL替换HTML字符串中所有与URL相关的出现。ae
- 一个 纽约 è ntity -返回RE模式来处理HTML实体。by
-替换 为 -此简短函数请求实际的url替换(rel_to_abs
)。此功能可能称为数百次(如果不是数千次)。注意不要在此功能(自定义)中添加慢速算法。cr
- ç reate ř E放置-创建并执行一个搜索和替换。
示例:(href="..."
在任何HTML标记内)。cri
- ç reate ř E放置 我 n第-创建并执行一个搜索和替换。
示例:url(..)
在style
HTML标记内的all 属性内。
测试用例
打开任何页面,然后将以下书签粘贴到位置栏中:
javascript:void(function(){var s=document.createElement("script");s.src="http://rob.lekensteyn.nl/rel_to_abs.js";document.body.appendChild(s)})();注入的代码包含上面定义的两个功能,以及如下所示的测试用例。 注意 :测试用例 不会
修改页面的HTML,但是会在文本区域(可选)中显示已解析的结果。
var t=(new Date).getTime(); var result = replace_all_rel_by_abs(document.documentElement.innerHTML); if(confirm((new Date).getTime()-t+" milliseconds to executennPut results in new textarea?")){ var txt = document.createElement("textarea"); txt.style.cssText = "position:fixed;top:0;left:0;width:100%;height:99%" txt.ondblclick = function(){this.parentNode.removeChild(this)} txt.value = result; document.body.appendChild(txt);}


