标签:
在上篇日志中(链接),我们讨论了utf-8编码和GBK编码之间转化的乱码问题,这一篇我们讨论Unicode(utf-16编码方式)与GBK编码之间转换的乱码问题。
在Windows系统自带的记事本中,我们按照图中所示使用Unicode编码保存。
在Visual Studio 2005中,单击“文件|高级保存选项”中选择Unicode-代码页1200。
按照上一篇日志中的方法,我们使用WinHex软件查看文件的16进制数据,如下:
其中,头两个字节“FF FE”代表utf-16的BOM码,从D4开始就是数据,即:
0xd4 0x00 0xda 0x00 0xb4 0x00 0xcb 0x00 0xcc 0x00 0xed 0x00 0xbc 0x00 0xd3 0x00 0xd7 0x00 0xa8 0x00 0xd3 0x00 0xc3 0x00 0xb4 0x00 0xfa 0x00 0xc2 0x00 0xeb 0x00 0xba 0x00 0xcd 0x00 0x2f 0x00 0xbb 0x00 0xf2 0x00 0xb5 0x00 0xf7 0x00 0xd3 0x00 0xc3 0x00 0xbb 0x00 0xf9 0x00 0xc0 0x00 0xe0 0x00
我们同时找出正确字符的GBK编码值
0xd4 0xda 0xb4 0xcb 0xcc 0xed 0xbc 0xd3 0xd7 0xa8 0xd3 0xc3 0xb4 0xfa 0xc2 0xeb 0xba 0xcd 0x2f 0xbb 0xf2 0xb5 0xf7 0xd3 0xc3 0xbb 0xf9 0xc0 0xe0
我们很容易发现,只要将偶数列中的0x00数消除就可以了,当然,我们格式也从utf-8变为GBK了。
对应的C语言程序如下:
#include <stdio.h> #include <stdlib.h> int main(int argc, char const *argv[]) { FILE* fp; FILE* fp2; //打开存储乱码的文件,utf-16编码格式,二进制打开 if((fp2=fopen("BadCode.txt","rb+"))==NULL) { printf("Open Source File Failed!\n"); system("pause"); exit(1); } //打开、新建存储处理后数据的文件 if((fp=fopen("BadCodeH.txt","w+"))==NULL) { printf("Open/Create Destination File Failed!\n"); system("pause"); exit(1); } //乱码第一个高位字节 unsigned ch; //乱码第一个低位字节 unsigned cl; //乱码第二个高位字节 unsigned ch2; //乱码第二个低位字节 unsigned cl2; ch=fgetc(fp2); //丢弃BOM字节信息 if(ch==0xff) { fgetc(fp2); ch=fgetc(fp2); } cl=fgetc(fp2); while(!feof(fp2)) { //乱码,接着读取两个字节,再丢弃偶数字节 if (ch>0x7f && cl==0x00) { ch2=fgetc(fp2); cl2=fgetc(fp2); fputc(ch,fp); fputc(ch2,fp); } //ASCII码,丢弃偶数字节 else { fputc(ch,fp); } ch=fgetc(fp2); cl=fgetc(fp2); } fclose(fp); fclose(fp2); system("pause"); return 0; }
运行结果如下:
和上一篇日志中分析的差不多,对于正常的utf-16编码的字符,我们只要将其转换为GBK编码输出就可以了,需要注意的是,正常的utf-16字符编码在文件中的存储方式:高位字节存放编码的后两位,低位字节存放编码的前两位。
C语言程序如下,戳此处下载UnicodeToGBK.txt文件:
#include <stdio.h> #include <stdlib.h> //读取utf-16和GBK转换表中的数据 bool ReadMap(unsigned* mapValue) { //声明文件指针 FILE* fp; //以可读写方式打开映射数据的文本文件 if (NULL == (fp = fopen("UnicodeToGBK.txt", "r+"))) { printf("Error!"); system("pause"); return false; } //存储Unicode的16进制数据的字符串 char utfStr[4]; //存储gbk的16进制数据的字符串 char gbkStr[4]; //存储Unicode16进制数据 unsigned utfId; //存储gbk的16进制数据 unsigned gbkId; //处理字符的临时变量 char c; //读取数据 while(!feof(fp)) { //读Unicode值的字符串 fread(utfStr,4,1,fp); //转换为整型 sscanf(utfStr,"%4x",&utfId); fgetc(fp); //读gbk值的字符串 fread(gbkStr,4,1,fp); //转化为整型 sscanf(gbkStr,"%4x",&gbkId); fgetc(fp); //赋值 mapValue[utfId]=gbkId; } fclose(fp); return true; } int main(int argc, char const *argv[]) { FILE* fp; FILE* fp2; //打开存储乱码的文件,utf-16编码格式,二进制打开 if((fp2=fopen("BadCode.txt","rb+"))==NULL) { printf("Open Source File Failed!\n"); system("pause"); exit(1); } //打开、新建存储处理后数据的文件 if((fp=fopen("BadCodeH.txt","w+"))==NULL) { printf("Open/Create Destination File Failed!\n"); system("pause"); exit(1); } unsigned mapValue[65536]; if(!ReadMap(mapValue)) { printf("Convert Failed!\n"); system("pause"); exit(1); } //乱码第一个高位字节 unsigned ch; //乱码第一个低位字节 unsigned cl; //乱码第二个高位字节 unsigned ch2; //乱码第二个低位字节 unsigned cl2; //存储utf-16编码的值 unsigned utf; //存储gbk编码的值 unsigned gbk; ch=fgetc(fp2); //丢弃BOM字节信息 if(ch==0xff) { fgetc(fp2); ch=fgetc(fp2); } cl=fgetc(fp2); while(!feof(fp2)) { //乱码,接着读取两个字节,再丢弃偶数字节 if (ch>0x7f && cl==0x00) { ch2=fgetc(fp2); cl2=fgetc(fp2); fputc(ch,fp); fputc(ch2,fp); } //ASCII码,丢弃偶数字节 else if(ch<=0x7f && cl==0x00) { fputc(ch,fp); } //否则就是正常字符,进行编码转换后输出 else { utf=cl*256+ch; gbk=mapValue[utf]; fputc(gbk/256,fp); fputc(gbk%256,fp); } ch=fgetc(fp2); cl=fgetc(fp2); } fclose(fp); fclose(fp2); system("pause"); return 0; }
例子如下:
未来我会将两篇文章中的程序进行整合,写一个图形界面的程序出来。
若有错误,恳请各位大侠指教~~
关于解决乱码问题的一点探索之二(涉及Unicode(utf-16)和GBK)
标签:
原文地址:http://www.cnblogs.com/xyb930826/p/4657462.html