关于解决乱码问题的一点探索之二(涉及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 ...
随机推荐
- Windows系统Python 虚拟环境virtualenv安装
1.我们用pip安装virtualenv >pip3 install virtualenv 2.创建工程目录 >mkdir myproject 3.进入工程目录 >cd myproj ...
- Linux了解一下
VMware与CentOS系统安装 1, 下载CentOS系统ISO镜像: 国内镜像源 https://opsx.alibaba.com/mirror#阿里云官方镜像站 iso下载地址(此DVD映像包 ...
- ubuntu系统部署python3.6.4
Ubuntu的版本为16.04,系统自带的Python版本较低,使用亲本版本3.6.4,下为安装步骤: 一.官网下载Python3.6.4版本 新建目录: sudo mkidr /usr/local/ ...
- 2014年第五届蓝桥杯B组(C/C++)预赛题目及个人答案(欢迎指正)
参考:https://blog.csdn.net/qq_30076791/article/details/50573512 第3题: #include<bits/stdc++.h> usi ...
- 【课堂实验】Arrays和String单元测试
实验内容 在IDEA中以TDD的方式对String类和Arrays类进行学习 测试相关方法的正常,错误和边界情况 String类 charAt split Arrays类 sort binarySea ...
- 实验五 Java网络编程
实验五 Java网络编程 实验五 Java网络编程 实验五所涉及的密码学算法及编程思路 ## Java对称加密-DES算法 (1) 获取密钥生成器 KeyGenerator kg=KeyGenerat ...
- vim 多个文件切换
打开多个文件:1.vim还没有启动的时候:在终端里输入 vim file1 file2 ... filen便可以打开所有想要打开的文件2.vim已经启动输入:open file可以再打开一个文件,并且 ...
- 【JUC源码解析】ConcurrentHashMap
简介 支持并发的哈希表.其中包括红黑树,扩容,分槽计数等知识点. 源码分析 常量 private static final int MAXIMUM_CAPACITY = 1 << 30; ...
- JS基础,相亲,逻辑训练
简单逻辑 <script> var a = prompt("有房么?"); // if(a == "有") { alert("结婚吧&qu ...
- Maven学习(十二)-----Maven POM
Maven POM POM代表项目对象模型.它是 Maven 中工作的基本单位,这是一个 XML 文件.它始终保存在该项目基本目录中的 pom.xml 文件.POM 包含的项目是使用 Maven 来构 ...