Unicode、ANSI、UTF

Easter79
• 阅读 765

最近在写网络通信上的一些东西,快被这些编码格式搞崩溃了。

一、什么是编码

  编码是对现有“符号”进行转化,可以存储在计算机中,在没有计算机时,我们的使用的“符号”,都是手写的,我们的大脑对其编码,这样我们就能记住和识别。但计算机只能存储电信号,即二进制。所以,我们需要对其编码,能使计算机储存。

  各个国家和地区所制定了不同 ANSI 编码标准中,都只规定了各自语言所需的“字符”。这样就不利于交流,所以就有了Unicode编码。

  名词解析:

  1.ANSI:众所周知,刚开始计算机是在美国出现的,所以他们也是第一批考虑编码的,第一开始由于只是用于计算,所有,只用了ASCII码,但后来计算机飞速发展,已经不仅仅用于计算。所以美国就提出了ASNI标准来进行编码。后来,中日韩等又提出了自己的编码编码,例如中国的GBK,但还是统称为ANSI标准。因此它是一个编码集,并不是特定指一种编码格式。

  2.Unicode:这个又称万国码,设计的初衷就是设计出一种通用的编码集。

  3.UTF-8:这是Unicode的一种实现方式。Unicode设计初衷是好的,但是由于是万国码,所以要用4个字节来进行编码,但是,如果使用Unicode编码,存储英文字符和数字时,就会浪费存储空间,因此需要使用一种能减少存储空间的方法。UTF-8就应运而出。

二、utf-8具体实现。

Unicode符号范围      | UTF-8编码方式

(十六进制)                 | (二进制)

----------------------+---------------------------------------------

0000 0000-0000 007F | 0xxxxxxx

0000 0080-0000 07FF | 110xxxxx 10xxxxxx

0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx

0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

其中x填入的即是对应的Unicode编码。

UCS-2和UCS-4

Unicode是为整合全世界的所有语言文字而诞生的。任何文字在Unicode中都对应一个值,这个值称为代码点(code point)。代码点的值通常写成 U+ABCD 的格式。而文字和代码点之间的对应关系就是UCS-2(Universal Character Set coded in 2 octets)。顾名思义,UCS-2是用两个字节来表示代码点,其取值范围为 U+0000~U+FFFF。

为了能表示更多的文字,人们又提出了UCS-4,即用四个字节表示代码点。它的范围为 U+00000000~U+7FFFFFFF,其中 U+00000000~U+0000FFFF和UCS-2是一样的。

要注意,UCS-2和UCS-4只规定了代码点和文字之间的对应关系,并没有规定代码点在计算机中如何存储。规定存储方式的称为UTF(Unicode Transformation Format),其中应用较多的就是UTF-16和UTF-8了。

三、怎么对编码进行转换。

  首先要明确一个概念,由于网络中大部分都是利用utf-8进行编码的(这是因为utf-8通用,且同样的内容所占字节更少)。我们所谓的转换编码,大部分是转换到utf-8利于传输,但utf-8仍然属于Unicode编码,所以就会有这样一个逻辑关系。

  ANSI(GBK)需先转换到 Unicode,从Unicode在转换为utf-8,反之亦然。

  首先是ANSI转换为Unicode:这一步,是我刚开始最不理解的。因为底层编码都是不同。利用汉字“严”。其Unicode编码为 4E25,但其GBK 编码为:D1CF。查了一点资料,发现和自己想的一样,是利用对应的编码表转换。

  其次是Unicode转换为UTF-8。这一步,了解到具体的UTF-8的构成,我们就可以很容易搞懂其具体原理。

四、我所找到的函数

  声明:以下函数均摘自别人博客。

  1.UTF-8和GBK互转。

    这与我前面所述,并无冲突。只是隐含了转到Unicode这一过程。这是利用 WindowsAPI来实现的。

    传送门:

      https://blog.csdn.net/xiaohu\_2012/article/details/14454299

#include<windows.h>
#include<string>
std::string UTF8ToGBK(const char* strUTF8)

{

    int len = MultiByteToWideChar(CP_UTF8, 0, strUTF8, -1, NULL, 0);

    wchar_t* wszGBK = new wchar_t[len + 1];

    memset(wszGBK, 0, len * 2 + 2);

    MultiByteToWideChar(CP_UTF8, 0, strUTF8, -1, wszGBK, len);

    len = WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, NULL, 0, NULL, NULL);

    char* szGBK = new char[len + 1];

    memset(szGBK, 0, len + 1);

    WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, szGBK, len, NULL, NULL);

    std::string strTemp(szGBK);

    if (wszGBK) delete[] wszGBK;

    if (szGBK) delete[] szGBK;

    return strTemp;

}
std::string GBKToUTF8(const char* strGBK)

{

    int len = MultiByteToWideChar(CP_ACP, 0, strGBK, -1, NULL, 0);

    wchar_t* wstr = new wchar_t[len + 1];

    memset(wstr, 0, len + 1);

    MultiByteToWideChar(CP_ACP, 0, strGBK, -1, wstr, len);

    len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);

    char* str = new char[len + 1];

    memset(str, 0, len + 1);

    WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, NULL, NULL);

    std::string strTemp = str;

    if (wstr) delete[] wstr;

    if (str) delete[] str;

    return strTemp;

}

    这里利用的是Windows API:

            MultiByteToWideChar()

            WideCharToMultiByte()    需要说明的vs编辑问题。https://blog.csdn.net/a3192048/article/details/82154194 

    工程属性里,字符集可以选择“使用Unicode字符集”和“使用多字节字符集”。此选项只控制代码里的API是用宽字符版(即Unicode)的还是ANSI字符版(即GBK)的,它控制不了代码里的字符是用Unicode编码还是ANSI编码。

    如果选择了“使用Unicode字符集”,则代码里用到的API被解释为Unicode版本的API(带标记W的API),如MessageBox被解释为MessageBoxW;
    如果选择了“使用多字节字符集”,则代码里用到的API被解释为ANSI编码版本的API(带标记A的API),如MessageBox被解释为MessageBoxA。

    这里真是纠结半天,其实我们编写的代码页仍然是系统默认的编码集,Windows一般是gbk。还有你在vs中设置保存为 utf-8时,会发现你不能在程序中,使用汉字字符串。这也是vs最坑爹的地方。

  2.UCS-2转utf-8。这就是Unicode转utf-8。

  传送门:https://blog.csdn.net/go\_to\_learn/article/details/8048472

五、我的感悟

  写了一个传输utf-8的简单通信,这个编码就能困扰我两天。c++对这些底层编码真是没有现成的库。不像Java那样封装好了。Java中一行代码就可以搞定的事,我自己折腾了好久。不过也真正懂得了编码的概念。以前经常混淆。

  碰壁之处:

    我的传输数据中有汉字,需要转码成utf-8进行传输,否则服务器会识别不出来我传输的数据。由于字符和英文属于127的字符。Unicode和GBK都是相同的。不存在转码问题。只有汉字需要转码。

  解决方法:

    在封装数据包时,将汉字转码为utf-8格式。由于 特殊字符和英文在utf-8和gbk中都相同。所以我们封装的数据包就相当于utf-8的数据包,虽然我们只转码了汉字。这样服务器就可以正常解析了。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
Easter79
Easter79
Lv1
今生可爱与温柔,每一样都不能少。
文章
2.8k
粉丝
5
获赞
1.2k