解决android手机导出的通讯录vcf文件乱码方法

菲菲OSC 发布于 2014/02/17 01:06
阅读 5K+
收藏 2
导出的 vfc 文件如下
BEGIN:VCARD
VERSION:2.1
N;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:;=E9=BB=8E=E4=B8=BD=E7=BE=8E;;;
FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E9=BB=8E=E4=B8=BD=E7=BE=8E
TEL;CELL:+861380080000
ORG;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=31=33=37=E5=88=9B=E4=B8=9A
END:VCARD


无论导入EXCEL 或 Address Book,这堆符号“=31=33=37=E5=88=9B=E4=B8=9A” 总是乱码

于是百度搜索,在快手官网搜索,在开源库源码搜索,终于找到解决方法

由于标准库源码的编码及解码未能满足要求,那么就自己参照库源码重写函数,虽然还不知道其语句具体意思,但能达到结果就是成功了,解决了VCF文件乱码就好办了。可以做联系人数据备份了。

上码:

import console
var t1 = "=31=33=37=E5=88=9B=E4=B8=9A"
// 解码
decode = function(s,utf8){
    s = string.replace(s,"<\=\x\x>+",
        function(c){   
            return eval("'" + ( string.replace( c,"\=","\\x") ) + "'" )  
        }
    ) 
  if(utf8) s= string.fromto(s,65001,0);
  return s; 
}

// 编码
encode = function(s,utf8){   
	if(utf8) s = string.fromto(s,0,65001);
	s = string.replace(s,"[^\.\-\_\~]",
		function(c){  
			return string.format("%%%02X", c[1] )
		}
	)  
	return string.replace(s,"<%+>","=")
}

var t2 = decode(t1,"utf-8")
var t3 = encode(t2,"utf-8")
console.log("解码:",t2 );
console.log("编码:",t3 );



加载中
1
figer1
figer1

这是Quoted Printable编码,与Base64同属MIME内容传输编码,
Quoted Printable 与UrlEncode类似用16进制编码字符。所以您引用UrlEncode编解码的代码结果是正确的。

关于这段代码的解释:

string.replace() 是一个字符串替换函数,
参数二是模式表达式(使用简化的类正则语法),参数三可以是替换字符串或替换函数, "<\=\x\x>+" 中的"\x"表示十六进制字符,这里表示一个等号后面两个十六进制字符。 而<>表示一个原子字符串,"+"则表示该字符串重复一次或多次。

string.format("%%%02X", c[1] ) 这个函数格式化参数并生成字符串。
"%X" 表示将数值参数格式化为十六进制字符串 "%02X" 表示十六进制至少为两位,不足补0 而最前面的"%%"则表示普通的字面的"%"字符。

return string.replace(s,"<%+>","=") 实际上可以改为 return string.replace(s,"%,"=") 其实这句也是不必要的,你可以在前面直接使用 string.format("=%02X", c[1] ) 就行。

0
菲菲OSC
菲菲OSC

编码太多,各个算法都不一样,都搞晕了!!!

谢谢@figer1 解释,有点明白函数用法了,上面代码照搬inet.url库源码的,根据你的建议修改代码如下

import console
var t1 = "=31=33=37=E5=88=9B=E4=B8=9A"
// 解码
decode = function(s,utf8){
    s = string.replace(s,"<\=\x\x>+",
        function(c){   
            return eval("'" + ( string.replace( c,"\=","\\x") ) + "'" )  
        }
    ) 
	if(utf8) s= string.fromto(s,65001,0);
	return s; 
}

// 编码
encode = function(s,utf8){   
	if(utf8) s = string.fromto(s,0,65001);
	return  string.replace(s,"[^\.\-\_\~]",
		function(c){  
			return string.format("=%02X", c[1] )
		}
	)  
}

var t2 = decode(t1,"utf-8")
var t3 = encode(t2,"utf-8")
console.log("解码:",t2 );
console.log("编码:",t3 );



0
菲菲OSC
菲菲OSC

另外,我发现了string.quotedPrintable扩展库,也是编码解码,但同样地,137这个不能编码,不知道如何修改 string.quotedPrintable 让137 编码,还有,如果137不编码,能否导入手机联系人呢?因为这个是手机导出来的

//quotedPrintable 编码
namespace string.quotedPrintable;
 
var push = ..table.push;
var sub = ..string.sub;
var format = ..string.format;

decode = function(s,utf8){
	var c;
    var out = {};
    if(!s) error("参数不能为字值",2);
    
	for( i=1;#s ){
		c = s[i];
		if( c == '='# ){
			if( ! ( s[i+1]=='\r'# && s[i+2] == '\n'# ) ){
				c = tonumber( sub(s,i+1,i+2),16)
				if( c === null ) return null,"格式错误1" + sub(s,i);
				push( out,c ); 
			} 
			i+=2;
		}
		else if( c >= 0x20 && c <= 0x7f || c='\t' || c ='\r' || c = '\n'){
			push( out,c );
		}
		else {
			return null,"格式错误2" + sub(s,i);
		}
	} 
	s = ..string.pack(out);
	if( utf8 ) s = ..string.fromto(s,65001,0);
	return s;
}

encode = function(s,utf8){
	var c; 
	var len = 0;
    var out = {};
    if(!s) error("参数不能为字值",2)
    
    if( utf8 ) s = ..string.fromto(s,0,65001);
    for(i=1;#s;1){ 
    	if( len >= 70 ){ 
    		push( out,'=\r\n');  
    		len = 0;
    	}
    	c = s[i];
    	if( c >= 33 && c <= 126 && c!='='# ){
    		push( out,s[[i]] )
    		len++;
    	}
    	else{
    		push( out,format("=%02X", c )  ) 
    		len+=3;
    	}
    }
    return ..string.join(out)
}  

/**intellisense(string.quotedPrintable)
encode( = 编码
encode(.("字符串",是否进行UTF8编码) = 参数@2可选\n返回字符串
decode( = 解码
decode(.("字符串",是否UTF8编码) = 参数@2可选\n成功返回字符串,失败返回null,错误信息
end intellisense**/



菲菲OSC
菲菲OSC
回复 @figer1 : 谢谢
figer1
figer1
Quoted Printable 编码规定数字、字母等不需要编码,这是为了缩减编码后字符串的体积,所以137不需要编码,如果你要编码这些就不必要用这个扩展库了,因为几句代码就可以了。
返回顶部
顶部