关于解决乱码问题的一点探索之二(涉及Unicode(utf-16)和GBK)
在上篇日志中(链接),我们讨论了utf-8编码和GBK编码之间转化的乱码问题,这一篇我们讨论Unicode(utf-16编码方式)与GBK编码之间转换的乱码问题。
在Windows系统自带的记事本中,我们按照图中所示使用Unicode编码保存。

在Visual Studio 2005中,单击“文件|高级保存选项”中选择Unicode-代码页1200。

文件中只有乱码与ASCII码
按照上一篇日志中的方法,我们使用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;
}
运行结果如下:

更一般的情况(文件中有正常的中文字符,乱码和ASCII字符)
和上一篇日志中分析的差不多,对于正常的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)的更多相关文章
- 关于解决乱码问题的一点探索之一(涉及utf-8和GBK)
在使用Visual Studio 2005进行MFC开发的时候,发现自动添加的注释变成了乱码.像这样: // TODO: ÔÚ´ËÌí¼ÓרÓôúÂëºÍ/»òµ÷ÓûùÀà 还有这样: // ...
- mysql 使用set names 解决乱码问题的原理
解决乱码的方法,我们经常使用“set names utf8”,那么为什么加上这句代码就可以解决了呢?下面跟着我一起来深入set names utf8的内部执行原理 先说MySQL的字符集问题.Wind ...
- servlet 解决乱码问题
对于servlet大家应该都很熟悉了,今天再复习一下,如果有哪里写的不好或不对的地点希望广大的网友批评指正.今天只讨论get和post两w种方式,他们之间有很多的不同点,所以解决编码的方式也会不一样, ...
- 关于Mysql中文乱码问题该如何解决(乱码问题完美解决方案)(转)
这篇文章给大家介绍关于Mysql中文乱码问题该如何解决(乱码问题完美解决方案)的相关资料,还给大家收集些关于MySQL会出现中文乱码原因常见的几点,小伙伴快来看看吧 最近两天做项目总是被乱码问题困 ...
- SpringMVC解决乱码
SpringMVC解决乱码 在web.xml中配置如下代码
- http get/post解决乱码问题
<form method="默认为get"-> <s:form mothod="默认为post"-> ================= ...
- 上传Text文档并转换为PDF(解决乱码)
前些日子,Insus.NET有分享一篇<上传Text文档并转换为PDF>http://www.cnblogs.com/insus/p/4313092.html 它是按最简单与默认方式来处理 ...
- php 解决乱码的通用方法
一,出现乱码的原因分析 1,保存文件时候,文件有自己的文件编码,就是汉字,或者其他国语言,以什么编码来存储 2,输出的时候,要给内容指定编码,如以网页的形势输入时<meta http-equiv ...
- 为sublime安装package control 解决乱码问题 Mac版
为sublime安装package control Mac版参考 https://sublime.wbond.net/installation 防止中文乱码其实只需要2个东东 一个GBK enc ...
随机推荐
- hive的分桶
套话之分桶的定义: 分桶表是对列值取哈希值的方式,将不同数据放到不同文件中存储.对于 hive 中每一个表.分区都可以进一步进行分桶. 列的哈希值除以桶的个数来决定每条数据划分在哪个桶中.(网上其它定 ...
- 关于makefile中自动产生依赖的理解
本博文是在学习了<GNU Make中文手册>后记录下来的自己的关于自动产生makefile依赖的语句的理解,向大家分享. <GNU make中文手册>中的相关章节见一下链接: ...
- Python之路(五)-->> 格式化
在Python中格式化的方式有两种,一种是%,另外一种是format()格式化. ----------------------------------------------------------- ...
- 20155322 《Java程序设计》课堂实践项目 数据库-3-4
20155322 <Java程序设计>课堂实践项目 数据库-3-4 数据库-3 实践要求 参考教材代码完成下面的要求,提交能连接到world的截图(有学号水印),并提交代码的码云链接.查询 ...
- [note]左偏树(可并堆)
左偏树(可并堆)https://www.luogu.org/problemnew/show/P3377 题目描述 一开始有N个小根堆,每个堆包含且仅包含一个数.接下来需要支持两种操作: 操作1: 1 ...
- Zabbix学习之路(四)之Web监控
1.Zabbix监控web服务器访问性能 zabbix 对 web 性能的监控,通过它可以了解 web 站点的可用性以及性能.最终将各项指标绘制到图形中,这样我们可以了解到一个站点的下载速度.响应速度 ...
- Yii2.0 高级模版编写使用自定义组件(component)
翻译自:http://www.yiiframework.com/wiki/760/yii-2-0-write-use-a-custom-component-in-yii2-0-advanced-tem ...
- unity图形圆形展开
脚本如下: using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngi ...
- jenkins自动打包部署linux
需要用到2个插件. git parameter:用于参数化构建时选择分支. Publish Over SSH:用于上传jar包和操作tomcat 1.先在系统设置添加要连接的linux服务器,使用用户 ...
- 二、Django快速安装
一.安装Python 作为一个Python Web框架,Django依赖Python.从Django适用于哪些版本的Python可以获取更多信息.较新版本的Python内置一个轻量级的数据库SQLit ...