百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

Unicode,GBK和UTF8

liebian365 2025-03-05 17:46 8 浏览 0 评论

前言

其实这是个老生常谈的问题了,相信大家在第一次遇到Unicode编码问题时,都会在网上搜索一通,

找到几个解释,虽然有点杂乱,但还是感觉自己明白了些什么,然后就继续忙别的事情.

而我之所以就这个问题专门写一篇文章,原因是前两天在与公司一位有十几年工作经验的JAVA程序员对接

API时, 我问他返回的汉字是什么编码的, 而他回答说"直接返回unicode". 一个如此有经验的老程序员

对这种基本问题都不甚清楚, 因此我觉得还是有必要好好说一下这个问题的.

字符集

在介绍他们之间的区别时, 我们先讲下什么是Unicode. 简单来说,Unicode是一个字符集(character set),

和ASCII一样, 其作用是用一系列数字来表示字符(character), 这些数字有时也称为码点(code points).

在PC刚出来的时候,使用英文的几位先驱认为计算机需要表示的字符不多,26个英文字母加几个回车换行等

特殊符号,总共一百个字符顶天了,于是就有了ASCII. ASCII码的大小为1个字节,定义了128个字符,

分别表示为0-127. 比如字符'A'的码点为65,回车符'\n'的码点为10, 如下所示:

当然, 后来人们发现, 世界上的字符远远不止128个, 因此就需要一个新的字符集能表示世上所有的字符,

包括一个英文字符,一个汉字字符,一个象形文字等. 这个字符集就是Unicode. Unicode前向兼容了ASCII,

最多可以表示2^21(大概200万)个字符,已经足够囊括当今所有国家的文字, 如下所示:

目前unicode字符集表示完所有字符后还有剩余, 这些暂时用不到的部分通常用占位符FFFD表示.

字符编码

有了字符集, 我们现在可以用任意数字来表示现实中的字符了. 但字符要保存在计算机中,必须要先经过编码.

有人问, 数字直接保存在内存里不就行了吗? 但是用多少个字节表示一个数字,以及每个字节的范围这都是需要

预先约定的,这种约定就叫编码. 假如我们有四个数字,1,2,3,4要保存在计算机里, 如果约定了utf-8编码,

那么在内存中的表示则如下:

00000001 00000010 00000011 00000100

其他的编码规则有utf-16,gb2312,gbk等,具体的编码规则不在本文的范围内,想要深入了解的可以在网上查阅相关的文档.

因此,我们可以看到,如果不按照约定的规则来解码,就很有可能无法还原出原来的数据,也就是我们经常遇到的"乱码".

下面以几个例子来简单说明:

>>> u'你好'
u'\u4f60\u597d'
>>> u'你好'.encode('utf8')
'\xe4\xbd\xa0\xe5\xa5\xbd'
>>> u'你好'.encode('gbk')
'\xc4\xe3\xba\xc3'
>>> u'你好'.encode('utf8').decode('gbk')
u'\u6d63\u72b2\u30bd'
>>> print u'你好'.encode('utf8').decode('gbk')
浣犲ソ

如上面的代码所示, "你好"两个汉字字符的unicode分别为4f60和597d, utf-8编码后占6个字节, 而gbk编码后占4个字节.

如果用utf8编码后错误地用gbk来解码, 就会得到3个unicode码点,分别表示字符,;而如果用gbk编码后

错误地用utf8来解码, 则在解码第二个字符时无法凑够3个字节, 因此会得到未知的结果, 甚至会因为内存越界访问引起程序异常.

注: 本文的python代码示例是在Linux Terminal下运行的, 因此默认为utf-8编码, 如果你是在Windows cmd里运行, 则通常默认GBK编码, 因此乱码会在不同地方出现:)

知道字符编解码的用法之后,我们就可以解释一下常见的一些乱码由来了, 比如在Windows下,未初始化的栈会初始化为0xcc, 未初始化的堆内存会初始化为0xcd, 可以看到前者为'烫'的gbk编码,而后者正好为'屯'的gbk编码, 如下所示:

u'\ufffd'
>>> u'烫'
u'\u70eb'
>>> u'烫'.encode('gbk')
'\xcc\xcc'
>>> u'屯'
u'\u5c6f'
>>> u'屯'.encode('gbk')
'\xcd\xcd'

前面也说过, unicode暂时没用到码点会用占位符FFFD来表示, 如果这个占位符被错误解析, 就会被当作有意义的内容了:

>>> u'\uFFFD'.encode('utf8')
'\xef\xbf\xbd'
>>> u'锟斤拷'.encode('gbk')
'\xef\xbf\xbd\xef\xbf\xbd'
>>> print (u'\uFFFD'.encode('utf8')*2).decode('gbk')
锟斤拷

可以看到,汉字"锟斤铐"(Unicode)的gbk编码分别为\xef\xbf, \xbd\xef和\xbf\xbd, 正好是unicode码FFFD的utf8编码 的叠加, 因此如果平时遇到多个utf8编码的Unicode占位符且不巧用了gbk的方式解码,那就会看到熟悉的锟斤铐了.

其他

在Windows的Notepad.exe中, 保存文件的格式可以看到有如下几种:

可刚刚不是说Unicode只是字符集吗, 为什么上面显示可以保存为Unicode"编码"? 好吧, 其实这是Windows在命名上一个操蛋的

地方. 因为Windows内部使用UTF-16小端(UTF-16LE)作为默认编码,并且认为这就是Unicode的标准编码格式. 在Windows的世界中,

存在着ANSI字符串(在当前系统代码页中, 不可拓展),以及Unicode字符串(内部以UTF16-LE编码保存). 因此notepad里所说的

Unicode大端,其实就是UTF16-BE.

这其实也不怪Windows, 因为这是在Unicode出现的早期设计的, 那时我们还没意识到UCS-2的不足, 而且UTF-8还没有被发明出来. 这也是为什么Windows对UTF8的支持如此之差的原因之一吧.

后记

说了这么多, 现在让我们回到一开始的问题, 如果有人问你"Unicode,GBK和UTF-8有什么区别?", 我想你应该知道该怎么回答了吧: Unicode是 一种字符集, 而GBK和UTF-8都是编码, 因此Unicode和后两者不是一类事物, 是无法进行对比的.

博客地址:

  • pannzh.github.io
  • 有价值炮灰-博客园

相关推荐

C语言自学课程大纲(c语言入门自学资料)

一、自学C语言,很多人不知道应该如何学习,从哪儿学习,学习又分为几个阶段,总是学着学着就很迷茫???分享C语言的学习路线图,跟着路线图学吧,天天看。...

「linux」定时器方案:红黑树、最小堆和时间轮的原理

一、网络事件和时间事件对于服务端来说,驱动服务端逻辑的事件主要有两个,一个是网络事件,另一个是时间事件;...

程序员怎么会不知道 C10K 问题呢?

昨天的文章中提到了C10K问题,结果好些程序员跑过来问,啥是C10K,我写了这么多年程序,我怎么不知道呢?我说,那你听说过前腿儿猪肉吗?今天简单说说C10K的问题。关于这个问题,Ruby...

朝荐开源 - glib(朝廷百科)

glib是一套通用的实用程序库,它为C语言提供了许多有用的数据结构、工具函数和抽象层,旨在简化C语言的跨平台开发,并提高代码的可重用性和效率。glib是GTK+和GNOME桌面环...

libevent总结(事件处理框架)(libevent libev)

libevent的事件处理框架是一个反应堆模型,而反应堆模型的核心就是io复用,拿epoll来说反应堆模型有两个核心数据结构,一个是epoll维护的内核事件表,一个是保存激活事件的事件队列当然,值得注...

日荐开源 - LibEvent(aldente官网网址)

libevent...

快递单号一键查询,高效追踪包裹物流,省时省力!

在繁忙的现代生活中,快递已成为我们日常生活中不可或缺的一部分。然而,面对众多的快递单号,如何快速、准确地查询包裹的物流信息成为了一个难题。现在,我们为您带来了一款快递单号一键查询工具,让您的物流追踪变...

导入不同快递公司下的单号批量查快递动态,一键解决物流查询难题

看着满屏快递单号陷入沉思?同事小王已经用《快递批量查询高手》一键导入多家快递,批量查询快递信息并统计了…而你还在中通、圆通、申通官网来回切换到鼠标冒烟?是时候亮出这个让快递公司接口“集体颤抖”的...

一键解锁快递查询高效能:批量查询快递,智能排序延误单号

当你的客服团队还在用5个浏览器轮番刷新物流页面时,隔壁仓库的王叔已经用快递批量查询高手把多个个滞留件变成会说话的预警红点!这篇教程将揭秘物流圈的「神器」,让「未更新快递」自动排队到你面前认罪。1.在软...

一站式快递单号查询平台,修改单号刷新快递信息的快递查询教程

一站式快递单号查询平台,支持导入单号查询时修改快递单号,高效刷新快递信息的快递查询教程随着电子商务的繁荣发展,快递业务量不断增长,无论是电商卖家还是普通消费者,对快递信息的查询和管理需求都日益增强。为...

高效快递单号查询,批量查询快递信息,多种查看方式满足你的需求

最近有很多朋友在问,如何查快递,怎么根据条件查看单号呢?不知道如何操作的宝贝们,下面请随小编一起来试试,希望能给大家带来帮助。需要哪些工具?安装一个快递批量查询高手快递单号若干怎么快速查询?步骤1:运...

物流查询达人必备!一键批量查询快递单号,根据发出时间筛选单号

嘿,各位快递查询达人们,是不是经常为海量的快递单号查询而头疼不已?想要一款能够在线批量查询快递动态,还能根据发出物流时间一键筛选所需快递单号信息的神器吗?来来来,让我给你们揭秘一款快递批量查询高手软件...

快递查询神器,多单号导入,筛选保存一键完成

当面对如山的快递单号,你是否曾感到手足无措?每一个单号都需要你逐一输入、查询,再逐个根据时间差进行筛选,这样的工作无疑是对耐心与精力的双重考验。但别担心,今天,我们将为你揭示一款物流行业的秘密武器——...

快递单号查询神器:一键复制粘贴,轻松批量追踪同公司快递

嘿,小伙伴们!还在为手动输入快递单号查询物流信息而烦恼吗?是不是觉得每次都要一个个输入单号,既费时又费力?别急,今天我要给大家介绍一款神奇的软件——快递批量查询高手!这款软件就像你的私人快递助手一样,...

快递单号查询入口自动批量查询快递动态并根据派件员字段排序单号

想象一下,面对堆积如山的快递单号,你不再需要一个个手动输入查询,而是轻轻一点,就能瞬间掌握所有快递的物流动态,甚至还能根据派件员智能排序,让管理变得井井有条。这不再是遥不可及的梦想,快递批量查询高手软...

取消回复欢迎 发表评论: