Unicode 字符和UTF编码的理解
Unicode 编码的由来
我们都知道,计算机的内部全部是由二进制数字0, 1 组成的, 那么计算机就没有办法保存我们的文字, 这怎么行呢? 于是美国人就想了一个办法(计算机是由美国人发明的),也把文字转化成数字,计算机不就能够保存文字了,所以美国人就制定了一张表,规定了文字与数字的一一对应,字符A 就对应数字65, 字符B 就对应数字66, 这张表就是著名的ASCII 码表。由于美国人的文字比较少,就是a, b, c d 等等, 对应完了,发现一共使用了128个数字,这也太少了,一个字节都没有使用了,所以就决定用一个字节来表示一个字符, 所以对于ASCII 码来说,一个字符在计算机中就占用一个字节。码表制定好了,生产计算机的时候直接把码表内置到计算机中就可以了。
但是随着计算机的推广,它到达了欧洲,亚洲,这就有点问题了,因为计算机中只有英文,它不可能表达 和书写其他国家的语言,比如汉语,日语等等, 这肯定也是不行的。于是各个国家的政府就制定各自的码表, 好让计算机也能表示本国的语言,就拿我国来说吧,GBK, GB2313 码表就出现了。 这就会出现一个问题,相同的数字在不同的码表中对应的文字可能不同, 这就有可能造成乱码。国际友人发了一封电子邮件过来,打开一看乱码了,各国之间的文件不能够交换使用。这时国际标准化组织就想把各国的字符都统一起来,把它们放到一张码表中,如果计算机中都内置这张表,那就不会出现乱码了。和ASCII码的想法一致,在这张表中,也是给每一个字符都分配一个独一无二的数字。这张表就是Unicode码表或Unicode编码字符集,这每一个字符对应的数字称之为做码点(Code Point). 码表的样子如下
Unicode 字符集在计算机中的实现
Unicode 字符集的基础非常简单,就是给世界上的每一个文字都分配一个独一无二的数字,这个数字称之为码点(code point), 比如 给字符A分配的数字是65, 给字符B 分配的数字是66,那么 A的 码点(code point)就是65, B 的code point 就是66. 但Unicode 相对于其他编码又是非常复杂的,这主要是在于Unicode 字符在计算机中的实现上,这些数字怎么在计算机中表示,用多少个字节?
由于当时提出制定Unicode字符集标准的时候,是在1990s 左右,那时各国的文字都比较少,都对应完了之后,发现并没有超过6万,正好在计算机中,两个字节就可以表示6万多个字,两个字节就是16个位(bit),无符号的话那么最大的数就是16个位都是1,这个数就是 2的16次方即 2^16-1 = 65536-1 = 65535所以就决定用2个字节,16个bit 来表示Unicode 字符, 这就是最早的UCS-2编码, 这16个bit 称之为code uint(码元), 这时 一个码点就对应一个码元。
但是随着时间的推移,尤其是亚洲国家把大量的象形文字也加入到Unicode 编码中,突然发现,65536的数量根本就装不下这些文字,于是Unicode 编码字符集也相应的进行了扩充,它把整个字符集分成了17个平面,每一个平面都能放2^16 个文字, 第一个平面就放置最初的UCS-2编码中所定义的文字,叫做基本多文本平面Basic Multilingual Plane (or BMP), 所以基本多文本平面码点的取值范围是0x0000 - 0xFFFF, 其他的16个平面称为补充平面(Supplementary Planes or Astral Planes), 它们的取值范围从0x10000 开始 (0xFFFF + 1 就等于0x10000, 16进制的计算) 。 针对这种多平面的字符集,出现了不同的在计算机中的实现方式,那就是我们经常听到的UTF-8, UTF-16, UTF-32.
UTF-16 就是对于在BMP 平面的文字用两个字节(16个bit)进行表示,然后对于其他平面的文字用四个字节进行表示,四个字节表示称之为surrogate pairs(代理对), 一对16 bit 来表示一个 字符。 由于一个16bit 称之为码元code unit, 一个字符对应的数字称为码点,这也就意味着,一个码点要有2个码元进行表示。
那怎么才能让一个码点用两个码元来显示呢? 先看一下目前Unicode 非基本面的有多少个字, 一共16个面, 一个面是2^16 个字,那也就是说,一共有16 * 2^16 个字, 就是2^20个字符, 也就需要20个二进制bit 位,一个码元只能16bit 位,那只能把20bit 位进行拆分成2个部分,一个部分占10个bit, 这样一个码元就可以表示了。但这又存在另外一个问题,当计算机去读取字符的时候,它碰到一个字节就去读取一个字节,它并不知道,你这个字节是拆分出来的,你会发现,本来一个字,确显示出了毫不相干的两个字,这怎么办呢?其实在usc-2 的时代,它所定义的Unicode 字符集并没有完全使用了2个字节,2个字节的后面一部分是空的,并没有对应任何字符,这一段是0xD800 到 0xDFFF(55296 - 65535), 这也就意味着,使用这一段上的码元没有任何问题。那我们就想办法,让非基本面的码点对应到这一段上来。对应的逻辑是这样的,首先把0xD800 - 0xDFFF 分为两个部分,0xD800 到 0xDBFF 和0xDC00 到 0xDFFF,然后再用码点减去65536, 把剩下的数用二进制表示,如果二进制不够20位,可以在前面补0. 再把20位二进制分为两个部分,每个部分占用10个bit, 前10个bit 对应到0xD800 - 0xDFFF, 称为高位(H), 后10个bit 对应到0xDC00 到 0xDFFF 称为低位(L), 这样一个码点就可以用两个码元(高位, 低位)进行表示了。映射比较复杂,不过Unicode 提供了一个公式,可以直接通过码点得到高低位码元。
H = Math.floor((c-0x10000) / 0x400)+0xD800 // c 是码点 0x10000 就是65536 0x400 就是1024, 0xD800 就是H 开始位置 L = (c - 0x10000) % 0x400 + 0xDC00 // 0xDC00 L 位开始的位置。
举一个小栗子,汉字"
Unicode 字符和UTF编码的理解的更多相关文章
- Java 字符编码(一)Unicode 字符编码
Java 字符编码(一)Unicode 字符编码 Unicode(http://www.unicode.org/versions/#TUS_Latest_Version) 是一个编码方案,说白了希望给 ...
- 谈谈对Java中Unicode、编码的理解
我们经常会遇到编码问题.Java号称国际化的语言,是因为它的class文件采用UTF-8,而JVM运行时使用UTF-16(至于为什么JVM中要采用UTF-16,我没看过 相关的资料,但我猜可能是因为J ...
- UNICODE UTF编码方式解析
先明确几个概念 基础概念部分 1.字符编码方式CEF(Character Encoding Form) 对符号进行编码,便于处理与显示 常用的编码方式有 GB2312(汉字国标码 2字节) ASCII ...
- 转载一篇关于unicode字符编码的文章
很久很久以前,有一群人,他们决定用8个可以开合的晶体管来组合成不同的状态,以表示世界上的万物.他们认为8个开关状态作为原子单位很好,于是他们把这称为"字节". 再后来,他们又做了一 ...
- 从ord()中对Unicode编码的理解
刚开始学习编程的时候,老对字符串编码的理解模模糊糊.也一直看这方便的资料,今天在看Dive in python时,突然有了新的理解(不知道是否正确). Python有个built-in函数ord(), ...
- decode 函数将字符串从某种编码转为 unicode 字符
环境:Ubuntu, Python 2.7 基础知识 这个程序涉及到的知识点有几个,在这里列出来,不详细讲,有疑问的直接百度会有一堆的. 1.urllib2 模块的 request 对像来设置 HTT ...
- 关于JAVA字符编码:Unicode,ISO-8859-1,GBK,UTF-8编码及相互转换
我们最初学习计算机的时候,都学过ASCII编码. 但是为了表示各种各样的语言,在计算机技术的发展过程中,逐渐出现了很多不同标准的编码格式, 重要的有Unicode.UTF.ISO-8859-1和中国人 ...
- ASCII, Unicode, UTF-8, 8进制, 16进制等各种编码学习理解笔记
字符编码的发展历史 Unicode和UTF-8有何区别? 在这个问题下的于洋的最高票回答中,比较完整地介绍了字符编码的发展历史,为了便于记忆,再次简要概括一番. 一个字节:最初一个字节的标准是混乱的, ...
- 初学者对ASCII编码、Unicode编码、UTF-8编码的理解
最早的计算机在设计时采用8个比特(bit)作为一个字节(byte),所以,一个字节能表示的最大的整数就是 255(二进制 11111111=十进制 255),如果要表示更大的整数,就必须用更多的字节. ...
随机推荐
- C#实现图像拖拽以及锚点缩放功能
本文主要实现C#窗体图像拖拽以及锚点缩放功能 1.新建Windows窗体应用项目,添加一个panel控件,在panel控件上添加picturebox控件 代码如下: using System; usi ...
- C# ctpclient networkstream 使用 BinaryReader的ReadString但是使用streamReader的Readtoend不行
BinaryReader.ReadString是和BinaryWriter.Write(string)使用详解链接:https://ask.csdn.net/questions/184965
- Transform the vot dataset into 4 corner format
Transform the vot dataset into 4 corner format Matlab code to change the 8 value ground truth into 4 ...
- mybatis自定义之优先从classes目录加载,加载之后遇到相同的类定义时不再加载
如果mybatis中包含了两个相同定义的mapper,启动时出现下列异常: Caused by: java.lang.IllegalArgumentException: Result Maps col ...
- 自己写的一个 CGBLIB 动态代理【原创】
CGLIB代理类,用CGLIB来实现一个代理类.大致原理描述如下: 1.使用Enhancer类来生成一个继续于被代理类的子类,此子类会重写被代理类(父类)中所有的非final的public方法: 2. ...
- Asynchronous method in while loop 构造异步调用链
Asynchronous method in while loop https://stackoverflow.com/questions/43064719/javascript-asynchrono ...
- jQuery-webcam使用
基本页面 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta ...
- Mac下 VirtualBox(VBox) 的 Centos6/7 共享文件夹配置
vbox 安装虚拟机请移步这里. https://blog.csdn.net/a47846800/article/details/88847466 前期准备: 远程登录 centos 系统, 分边执行 ...
- Ubuntu16.04下配置VScode的C/C++开发环境
博客转载:https://blog.csdn.net/weixin_43374723/article/details/84064644 Visual studio code是微软发布的一个运行于 Ma ...
- log4net记录多个级别文件
https://www.cnblogs.com/AprilBlank/p/12047757.html