https://www.cnblogs.com/zizifn/p/4716712.html

从字节理解Unicode(UTF8/UTF16)

如果你不知道或者不了解什么是Unicode/UTF8/UTF16,请详细阅读这篇文章(这也是这篇博文的先决条件):

学点编码知识又不会死:Unicode的流言终结者和编码大揭秘

但是如果你看完以上文章后,疑惑为什么一个Unicode:0x4F60(对应汉字是"你")会在UTF8下占用3个字节的存储空间。

按照排列组合2个字节完全可以存储多数unicode字符,明显字符"你"(0x4F60)是在2个字节最大可能范围内(0xFFFF)。

但是为什么UTF8却使用3个字节存储字符"你"呢?这样不是明显浪费存储空间吗?

答案不仅是UTF8没有浪费存储空间,而且UTF8还是一个精美的设计,至少在我看来。

Unicode/UTF8/UTF16

虽然你或许可能知道什么UTF8,但是我还是要简单介绍下什么是UTF8?什么是UTF16?什么是unicode?

看完我开头推荐的那篇详细的博文(学点编码知识又不会死:Unicode的流言终结者和编码大揭秘)。你应该知道unicode是一种索引表,它规定了任何字符的code。比如:字符"你"就是0x4F60,在整个宇宙(你确定是整个宇宙?)的任何地方,只要你用的是unicode,那么"你"的unicode就是"0x4F60"。

所以Unicode并不关心世界上有多少字符,如果你想把一个字符放入Unicode中,那么请告诉我你要放的是什么字符?那么Unicode会给你个索引号码?比如:汉字"你"就是"0x4F60"。也就是假如有一天人类统一了"三体星人"(可惜的是三体星已经被摧毁了。。),我们也可以把三体星文加入到Unicode中。

当然Unicode同样不关心你怎么实现,你怎么把字符编码成字节?所以unicode并不知道字符"你"占用几个字节。这时候就是UTF(Unicode Transformation Formats)来规定unicode字符该如何存储,占用几个字节?

总而言之:

Unicode定义世界每个字符的索引值。

UTF8/UTF16实现Unicode的标准,把字符存储到存储介质中。

从字节角度看UTF8

我们知道存储字节多少只和UTF有关,那么我们先看UTF8一张表.详情请查看wikipedia的介绍 。当然你看百度百科也是可以的。

Bits of

code point

First

code point

Last

code point

Bytes in

sequence

Byte 1

Byte 2

Byte 3

Byte 4

Byte 5

Byte 6

  7

U+0000

U+007F

1

0xxxxxxx

11

U+0080

U+07FF

2

110xxxxx

10xxxxxx

16

U+0800

U+FFFF

3

1110xxxx

10xxxxxx

10xxxxxx

21

U+10000

U+1FFFFF

4

11110xxx

10xxxxxx

10xxxxxx

10xxxxxx

26

U+200000

U+3FFFFFF

5

111110xx

10xxxxxx

10xxxxxx

10xxxxxx

10xxxxxx

31

U+4000000

U+7FFFFFFF

6

1111110x

10xxxxxx

10xxxxxx

10xxxxxx

10xxxxxx

10xxxxxx

根据这张表,我们可以知道0x4F60(字符"你")是在范围(0x0800-0xFFFF),所以在UF8下需要3个字节来存储。

下面让例子来阐述为什么需要3个字节?首先,先看下这3个字节存放的是什么?

在windows新建一个txt,写入字符"UTF8你"(加入UTF8是为了有个基准线查看"你"的真实字节值),然后另存为UTF8编码。用notepad++(需要装HEX-editor插件)或者Binary Viewer,查看"你"在UTF8下的16进制值。

我们知道字符"UTF8"16进制就是他们的ASNI码"0x55,0x54,0x46,0x38".那么字符"你"在UTF8下3个字节的值是"0xE4/0xBD/0xA0".

"0xE4"-->"11100100".

"0xBD"-->"10111101".

"0xA0"-->"10100000".

查看上面UTF8的表,表给出给出每个字节 的前几个固定的二进制数。

比如3个字节的Unicode会用到这个格式:"1110xxxx 10xxxxxx 10xxxxxx"来存储字符,对应到字符"你"就是"11100100 /10111101/ 10100000"。

拿出红色标注的部分"0100 111101 100000",转换成16进制就是"0x4F60"也就对应的是Unicode字符"你"。

现在我们可以知道UTF8固定每个字节的前面几位二进制值,然后用其他的位来表示字符。但是为什么UTF8的设计者们要这样设计呢?

我想这是UTF8为了兼容ASNI所要付出的代价,请查看上表,UTF8下是完全兼容asni,也就是asni标准的下的文档,在UTF8下显示完全不是问题(因为ASNI存储字节值和UTF8是一样的)。字符都是一个一个字节存储的,UTF8肯定是一个一个字节的读取,那么UTF8怎么在完全兼容ASNI前提下,是怎么知道某个字符是需要额外字节信息的?UTF8只有固定前几位二进制来决定这个字符需要以后的几个字节,又因为为了兼容ASNI,所以额外字节也需要固定前2位"10xxxxxx",来决定这个字节值不是代表ASNI字符。ASNI的格式是“0xxxxxxx”。

另外,你也完全可以自己实现一个标准来解释Unicode,比如就叫做UTF9吧,只要你能完全解释Unicode。

实际上是有UTF7,UTF8,UTF16,UTF32的。

从字节角度看UTF16

同样的,我们把txt:"UTF8你"另存为UTF16编码(windows下unicode编码就是指UTF16)。

UTF16下的每个字符需要是2个或者4个字节。

字符"UTF8"在UTF16下就是"0x55/0x0054/0x0045/0x0038",那为什么图片中是0x5500呢?这涉及到高字节序和低字节序。开头的那篇文章也有介绍。字节序仅仅就是先把字符的高位或者低位先放入存储的而已。

  1. 高字节序,高位字节被存在前面
  2. 低字节序,低位字节被存在前面

比如字符"你""0x4F60",第一个字节是"4F"是"高位",第二个字节是"60"是"低位".

稍微解释下为什么左边是高位,玩笑话就是想想你的银行账户当然是左面数值多才有意义啊。

那么按照"低字节序" "0x4F60"就被存储为"60 4F"拉。在intel CPU下默认是"低字节序"。

在UTF16下,存储的字节值和unicode是一一对应的。但是UTF16显示英文(asni)就浪费一个字节。所以英文国家用UTF8的编码比较多。反之其他国家用UTF16的较多。

字节顺序标记(BOM)

不知道你有没有注意到,在UTF16下的这张图,地址第0,第1位是"FF FE"

这就是BOM,通过FF FE或者FE FF来告诉解释器是那种字节序。

那么你也许会问,为什么UTF8没有字节序呢?那是因为UTF8是以字节为单位,一个一个字节读取。UTF16是以字为单位,一个一个字符(2个字节或者4个字节)读取,这样就会涉及先读取第一个或者第二个字节的情况。

希望这篇文章从存储字节角度看UTF8和UTF16会为给你带来不一样的感觉。

编码(2)从字节理解Unicode(UTF8/UTF16)的更多相关文章

  1. 从字节理解Unicode(UTF8/UTF16)

    如果你不知道或者不了解什么是Unicode/UTF8/UTF16,请详细阅读这篇文章(这也是这篇博文的先决条件): 学点编码知识又不会死:Unicode的流言终结者和编码大揭秘 但是如果你看完以上文章 ...

  2. 关于编码:Unicode/UTF-8/UTF-16/UTF-32

    关于编码,绕不开下面这些概念 ①Unicode/UTF-8/UTF-16/UTF-32 ②大小端字节序(big-endian/little-endian) ③BOM(Byte Order Mark) ...

  3. 细说:Unicode, UTF-8, UTF-16, UTF-32, UCS-2, UCS-4

    1. Unicode与ISO 10646 全世界很多个国家都在为自己的文字编码,并且互不想通,不同的语言字符编码值相同却代表不同的符号(例如:韩文编码EUC-KR中“한국어”的编码值正好是汉字编码GB ...

  4. 一句话理解字符编码(Unicode ,UTF8,UTF16)

    Unicode和ASCII码属于同一级别的,都是字符集,字符集规定从1到这个字符集的最大范围每个序号都各表示什么意思.比如ASCII字符集中序号65表示"A". 那接下来的UTF8 ...

  5. 字符编码详解及由来(UNICODE,UTF-8,GBK)[转帖]

    相信許多人對字符編碼都不是很了解,透過下文可以清晰的理解各种字符编码方式详解及由来. 一直对字符的各种编码方式懵懵懂懂,什么ANSI.UNICODE.UTF-8.GB2312.GBK.DBCS.UCS ...

  6. 字符编码详解及由来(UNICODE,UTF-8,GBK)

        一直对字符的各种编码方式懵懵懂懂,什么ANSI.UNICODE.UTF-8.GB2312.GBK.DBCS.UCS--是不是看的很晕,假如您细细的阅读本文你一定可以清晰的理解他们.Let's ...

  7. Unicode(UTF-8, UTF-16)令人混淆的概念

    为啥需要Unicode 我们知道计算机其实挺笨的,它只认识0101这样的字符串,当然了我们看这样的01串时肯定会比较头晕的,所以很多时候为了描述简单都用十进制,十六进制,八进制表示.实际上都是等价的, ...

  8. (转) Unicode(UTF-8, UTF-16)令人混淆的概念

    原文地址:http://www.cnblogs.com/kingcat/archive/2012/10/16/2726334.html 为啥需要Unicode 我们知道计算机其实挺笨的,它只认识010 ...

  9. Unicode(UTF-8, UTF-16)令人混淆的概念(转)

    文章转自http://www.cnblogs.com/kingcat/archive/2012/10/16/2726334.html (http://swiftlet.net/archives/cat ...

随机推荐

  1. Linux环境(Centos7)下部署.NetCore2.0的Web应用

    Web应用基于Windows环境下开发,然后部署到Linux 1.进入VS2017,点击新建->项目->.NetCore->ASP.NET Core Web应用程序,确定 2.选择W ...

  2. MySql技术内幕之MySQL入门(1)

    目录 MySql技术内幕之MySQL入门(1) 安装 关于注释 执行SQL语句 关于命令大小写 创建数据库 查看表的信息 查看更加详细的信息 查看与给定模式相匹配的列 插入数据 利用insert添加行 ...

  3. JAVA:简单添加菜单界面(swing)第二版

    环境:jdk1.8 package com.le.tool; import java.awt.Color; import java.awt.Container; import java.awt.Flo ...

  4. javascript小括号、中括号、大括号学习总结

    作为一名编程人员,和括号打交道是必不可少的.你可知道在不同的上下文中,括号的作用是不一样的,今天就让我们简单总结下javascript小括号.中括号.大括号的用法. 总的来说,JavaScript中小 ...

  5. OC重写init方法

    在创建一个对象的时候我们经常会用到init方法,单单是init只能是初始化,当我们在初始化的时候想要给这个对象加上默认的东西的时候, 系统提供的init方法就不能满足我们的需要,这时,就需要我们自己去 ...

  6. Java编程题(1):n个数里出现次数大于等于n/2的数

    题目描述:输入n个整数,输出出现次数大于等于数组长度一半的数. 输入描述:每个测试输入包含 n个空格分割的n个整数,n不超过100,其中有一个整数出现次数大于等于n/2. 输出描述:输出出现次数大于等 ...

  7. 写在HTTP协议之前

    1.网络模型 OSI模型即:开放系统互连参考模型(Open System Interconnect 简称OSI)是国际标准化组织(ISO)和国际电报电话咨询委员会(CCITT)联合制定的开放系统互连参 ...

  8. 手动模拟attach cinder volume的过程

    我们首先启动一台机器,启动的时候attach一个volume 创建一个空的cinder volume root:~# cinder create --display-name emptyvolume1 ...

  9. 关于c++的一篇随笔

    众所周知c++是一门极其深奥的学科,正因为其深奥之处,才会让人们觉得学习起来特别难.当然,我想说我自己也不例外,想起当初就像一场噩梦一样,直到今日还历历在目.尽管如此,c++还是一门相当有魅力的课程, ...

  10. 【腾讯Bugly干货分享】舞动的表情包——浅析GIF格式图片的存储和压缩

    本文来自于腾讯Bugly公众号(weixinBugly),未经作者同意,请勿转载,原文地址:https://mp.weixin.qq.com/s/v0pffOhjFWnVbU2lXjuEmw 导语 G ...