在上篇日志中(链接),我们讨论了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)的更多相关文章

  1. 关于解决乱码问题的一点探索之一(涉及utf-8和GBK)

    在使用Visual Studio 2005进行MFC开发的时候,发现自动添加的注释变成了乱码.像这样: // TODO: ÔÚ´ËÌí¼ÓרÓôúÂëºÍ/»òµ÷ÓûùÀà 还有这样: // ...

  2. mysql 使用set names 解决乱码问题的原理

    解决乱码的方法,我们经常使用“set names utf8”,那么为什么加上这句代码就可以解决了呢?下面跟着我一起来深入set names utf8的内部执行原理 先说MySQL的字符集问题.Wind ...

  3. servlet 解决乱码问题

    对于servlet大家应该都很熟悉了,今天再复习一下,如果有哪里写的不好或不对的地点希望广大的网友批评指正.今天只讨论get和post两w种方式,他们之间有很多的不同点,所以解决编码的方式也会不一样, ...

  4. 关于Mysql中文乱码问题该如何解决(乱码问题完美解决方案)(转)

    这篇文章给大家介绍关于Mysql中文乱码问题该如何解决(乱码问题完美解决方案)的相关资料,还给大家收集些关于MySQL会出现中文乱码原因常见的几点,小伙伴快来看看吧   最近两天做项目总是被乱码问题困 ...

  5. SpringMVC解决乱码

    SpringMVC解决乱码 在web.xml中配置如下代码

  6. http get/post解决乱码问题

    <form method="默认为get"-> <s:form mothod="默认为post"-> ================= ...

  7. 上传Text文档并转换为PDF(解决乱码)

    前些日子,Insus.NET有分享一篇<上传Text文档并转换为PDF>http://www.cnblogs.com/insus/p/4313092.html 它是按最简单与默认方式来处理 ...

  8. php 解决乱码的通用方法

    一,出现乱码的原因分析 1,保存文件时候,文件有自己的文件编码,就是汉字,或者其他国语言,以什么编码来存储 2,输出的时候,要给内容指定编码,如以网页的形势输入时<meta http-equiv ...

  9. 为sublime安装package control 解决乱码问题 Mac版

    为sublime安装package control   Mac版参考 https://sublime.wbond.net/installation 防止中文乱码其实只需要2个东东  一个GBK enc ...

随机推荐

  1. Flink-on-yarn

    介绍 官网下载 https://www.apache.org/dyn/closer.lua/flink/flink-1.6.1/flink-1.6.1-bin-hadoop28-scala_2.11. ...

  2. PHP中使用Redis接管文件存储Session详解

    前言 php默认使用文件存储session,如果并发量大,效率会非常低.而redis对高并发的支持非常好,可以利用redis替换文件来存储session. 最近就遇到了这个问题,之前找了网上的一套直播 ...

  3. Java ConcurrentHashMap 源代码分析

    Java ConcurrentHashMap jdk1.8 之前用到过这个,但是一直不清楚原理,今天抽空看了一下代码 但是由于我一直在使用java8,试了半天,暂时还没复现过put死循环的bug 查了 ...

  4. PTA(Basic Level)-1076 Wifi密码

    一 题目介绍:     现将 wifi 密码设置为下列数学题答案:A-1:B-2:C-3:D-4.本题就要求你写程序把一系列题目的答案按照卷子上给出的对应关系翻译成 wifi 的密码.这里简单假设每道 ...

  5. 关于Win10 环境下Quartus II 15.0器件列表无法下拉的解决方法

    不知大家在Windows 10 64位系统环境下使用Quartus II 15.0在新建工程时遇到过这种问题没,在新建工程的过程是选择器件的列表无法下拉,只能看到一个器件型号,如图1所示. 图1 开始 ...

  6. 团队展示网页 HTML模版

    之前帮着领导,参加了iGEM的校内赛的网页制作,一开始也是用的现成的模版,但后面修修改改几乎面目全非了- 这里分享一下自己的网站,可以用做团队展示的网页模版,文件在末尾,大家自行下载吧-- 这里贴两张 ...

  7. 第13届景驰-埃森哲杯广东工业大学ACM程序设计大赛--J-强迫症的序列

    链接:https://www.nowcoder.com/acm/contest/90/J 来源:牛客网 1.题目描述 牛客网是IT求职神器,提供海量C++.JAVA.前端等职业笔试题库,在线进行百度阿 ...

  8. 20155319 2016-2017-2《Java程序设计》课程总结

    20155319 2016-2017-2<Java程序设计>课程总结 每周作业链接 预备作业1:亦师亦友--我所期望的师生关系,对专业的认识与期望等 预备作业2:没有了自主,学习的小船说翻 ...

  9. 【转载】Ogre3d 2.1 源码编译安装教程

    原文:Ogre3d 2.1 源码编译安装教程 今年是3D手游年,今年也是游戏引擎战争进入白热的一年. 移动游戏的红海时代,让各大端游也忍不住纷纷伸出大白腿,Unreal.CryEngine纷纷宣布自己 ...

  10. Django模型层:单表操作

    一 ORM简介 查询数据层次图解:如果操作mysql,ORM是在pymysq之上又进行了一层封装