一、背景
我们使用svn pre-commit hook做了一个svn锁定的功能,对于在上线前的svn提交进行控制,防止开发及策划胡乱提交,导致线上bug。这个平台有一个web界面功能,可以争对性给某些人开通一次提交权限,并记录他这一次的提交文件和log,乱码就出现了,web界面上显示的中文均乱码,包括log和提交文件名称
乱码的格式是:/design/X_?229?175?188?229?133?165?230?149?176?230?141?174/04_?233?129?147?229?133?183?230?149?176?230?141?174?232?161?168/?229?149?134?229?186?151?230?149?176?230?141?174?232?161?168.xls 这样的;
例如web上乱码为:
14370127901362.png
对应实际的中文汉字为:
14370128636098.png
二、原因
字符编码的问题,大家都知道,主要是ascii编码和unicode、utf-8之间的转换。关于字符编码,可以看阮一峰老师的文章,解析简单透彻:http://www.ruanyifeng.com/blog ... .html
上述乱码基本是?229格式的,其中的?应该是svn自己加的分隔符,后面的三位数字为ascii编码,我们可以通过ascii转字符的函数将它转换成字符,将上述所有ascii字符拼接到一起即可形成unicode编码,然后再转utf-8,即可得到UrlEncode之后的中文汉字,然后再UrlDecode即可;
三、解决
知道上述原理之后,我采用js解决,这样不用修改后端代码,服务器也不用reload,调试也会方便一些;如果你才用其他语言,比如python、java、php等去解析乱码。可以找对应的函数替换即可。
3.1 urldecode和urlencode
比如:http://www.111cn.net /%E5%88%86%E5%B8%83%E5%BC%8F.html 这个链接里面的%E5%88%86%E5%B8%83%E5%BC%8F就是UrlEncode之后的中文,使用UrlDecode即可得到汉字“分布式”。关于这部分,网络博客很多,随便找;
Javascript方法如下:
function UrlDecode(zipStr){
var uzipStr="";
for(var i=0;i<zipStr.length;i++){
var chr = zipStr.charAt(i);
if(chr == "+"){
uzipStr+=" ";
}else if(chr=="%"){
var asc = zipStr.substring(i+1,i+3);
if(parseInt("0x"+asc)>0x7f){
uzipStr+=decodeURI("%"+asc.toString()+zipStr.substring(i+3,i+9).toString());
i+=8;
}else{
uzipStr+=AsciiToString(parseInt("0x"+asc));
i+=2;
}
}else{
uzipStr+= chr;
}
}
return uzipStr;
}
3.2 unicode转utf-8:EncodeUtf8
这部分代码网上找的,可能有bug,我用上没有什么问题,其他语言应该有更简单的方法:
function EncodeUtf8(s1) {
var s = escape(s1);
var sa = s.split("%");
var retV = "";
if (sa[0] != "") {
retV = sa[0];
}
for (var i = 1; i < sa.length; i++) {
if (sa[i].substring(0, 1) == "u") {
retV += Hex2Utf8(Str2Hex(sa[i].substring(1, 5)));
} else retV += "%" + sa[i];
}
return retV;
}
function Str2Hex(s) {
var c = "";
var n;
var ss = "0123456789ABCDEF";
var digS = "";
for (var i = 0; i < s.length; i++) {
c = s.charAt(i);
n = ss.indexOf(c);
digS += Dec2Dig(eval(n));
}
//return value;
return digS;
}
function Dec2Dig(n1) {
var s = "";
var n2 = 0;
for (var i = 0; i < 4; i++) {
n2 = Math.pow(2, 3 - i);
if (n1 >= n2) {
s += '1';
n1 = n1 - n2;
} else
s += '0';
}
return s;
}
function Dig2Dec(s) {
var retV = 0;
if (s.length == 4) {
for (var i = 0; i < 4; i++) {
retV += eval(s.charAt(i)) * Math.pow(2, 3 - i);
}
return retV;
}
return -1;
}
function Hex2Utf8(s) {
var retS = "";
var tempS = "";
var ss = "";
if (s.length == 16) {
tempS = "1110" + s.substring(0, 4);
tempS += "10" + s.substring(4, 10);
tempS += "10" + s.substring(10, 16);
var sss = "0123456789ABCDEF";
for (var i = 0; i < 3; i++) {
retS += "%";
ss = tempS.substring(i * 8, (eval(i) + 1) * 8);
retS += sss.charAt(Dig2Dec(ss.substring(0, 4)));
retS += sss.charAt(Dig2Dec(ss.substring(4, 8)));
}
return retS;
}
return "";
}
3.3 解析SVN乱码
解析SVN格式乱码,获得每个字符的ascii,然后拼接unicode,然后转utf8,然后再UrlDecode,成功解析出汉字;
function svn_ascii_to_utf8(ori) {
s = ori.split('?');
//三个才是一个汉字,至少要有一个汉字
if (s.length < 3) {
return ori;
}
var ascii = '';
for(i in s) {
x = s[i];
if (x.length == 3) {
ascii += String.fromCharCode(x);
//console.log(ascii);
}
else if (x.length > 3) {
ascii += String.fromCharCode(x.substr(0, 3));
ascii += x.substr(3);
}
else {
//do nothing
}
}
return UrlDecode(EncodeUtf8(ascii));
}
然后再web页面显示的时候,将相应的乱码,调用s = svn_ascii_to_utf8(s)即可,有乱码转乱码,无乱码保持不变;