一、 ASCII码

上个世纪60年代,美国制定了一套字符编码,对英语字符与二进制位之间的关系,做了统一规定。这被称为ASCII码,一直沿用至今。一个字节(8bit)一共

可以用来表示256种不同的状态。ASCII码一共规定了128个字符的编码,比如大写的字母A是65(二进制01000001)。这128个符号(包括32个不能打印

出来的控制符号),只占用了一个字节的后面7位,最前面的1位统一规定为0。

二、非ASCII编码

英语用128个符号编码就够了,但是用来表示其他语言,128个符号是不够的。比如,在法语中,字母上方有注音符号,它就无法用ASCII码表示。

于是,一些欧洲国家就决定,利用字节中闲置的最高位编入新的符号。比如,法语中的é的编码为130(二进制10000010)。这样一来,这些欧洲

国家使用的编码体系,可以表示最多256个符号。

但是,这里又出现了新的问题。不同的国家有不同的字母,因此,哪怕它们都使用256个符号的编码方式,代表的字母却不一样。比如,130在法语

编码中代表了é,在希伯来语编码中却代表了字母Gimel (ג),在俄语编码中又会代表另一个符号。但是不管怎样,所有这些编码方式中,0--127表

示的符号是一样的,不一样的只是128--255的这一段。

至于亚洲国家的文字,使用的符号就更多了,汉字就多达10万左右。一个字节只能表示256种符号,肯定是不够的,就必须使用多个字节表达一个符号。

比如,简体中文常见的编码方式是GB2312,使用两个字节表示一个汉字,所以理论上最多可以表示65536个符号。

三、Unicode

要想打开一个文本文件,就必须知道它的编码方式,否则用错误的编码方式解读,就会出现乱码。可以想象,如果有一种编码,将世界上所有的符号都

纳入其中,每一个符号都给予一个独一无二的编码,那么乱码问题就会消失。

2的16次方(65536)个号码组成一个平面

新的设计将字符集中的所有字符分为 17 个 代码平面(code plane)。

U+0000 ~ U+FFFF       基本多语言平面BMP(Basic Multilingual Plane),

U+10000 ~ U+10FFFF  辅助平面SMP (Supplementary Plane), 这些处于辅助平面的字符我们称作 增补字符(supplementary characters)。

四、Unicode的问题

需要注意的是,Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。

javascript使用Unicode字符集编写的

utf(Unicode Transformation Format)

4.1 UTF-32

4字节表示一个字符,完全对应Unicode编码,比如,字母a为0x00000061

缺点:浪费空间,比相同的ASCII编码文件大四倍

4.2 UTF-16

变长编码,长度为2或4字节

编号范围                                 字节 
0x0000 - 0xFFFF        2
0x010000 - 0x10FFFF      4

于是就有一个问题,当我们遇到两个字节,怎么看出它本身是一个字符,还是需要跟其他两个字节放在一起解读?

在基本平面内,从U+D800到U+DFFF是一个空段,即这些码点不对应任何字符。因此,这个空段可以用来映射辅助平面的字符。

U+D800到U+DBFF(空间大小210),称为高位(H),

U+DC00到U+DFFF(空间大小210),称为低位(L)。

这意味着,一个辅助平面的字符,被拆成两个基本平面的字符表示。

所以,当我们遇到两个字节,发现它的码点在U+D800到U+DBFF之间,就可以断定,紧跟在后面的两个字节的码点,

应该在U+DC00到U+DFFF之间,这四个字节必须放在一起解读。

Unicode码点转成UTF-16的时候,首先区分这是基本平面字符,还是辅助平面字符。如果是前者,直接将码点转为对应的十六进制形式,长度为两字节。


  1. U+597D = 0x597D

如果是辅助平面字符,使用转码公式:


  1. H = Math.floor((c-0x10000) / 0x400)+0xD800
  2. L = (c - 0x10000) % 0x400 + 0xDC00

下面通过将 U+64321 这个处于辅助平面的字符进行 UTF-16 编码的实例来讲解辅助平面字符的编码方式。

1、首先将这个字符的代码点减去 0x10000,得到长度为 20 bit 的一个值,这个值的范围必然在 0x0000 ~ 0xFFFF之内。

  1. V = 0x64321
  2. Vx= V - 0x10000
  3. = 0x54321
  4. = 0101 0100 0011 0010 0001

2、将 Vx 的高位 10 bit 的值作为高位代理的运算基数 Vh,将低位 10 bit 的值作为低位代理的运算基数 Vl。

这两个 10 bit 的值的取值范围都必然在 0x0000 ~ 0x3FF 之间。

  1. Vh = 0101 0100 00
  2. Vl = 11 0010 0001

3、将 Vh 和 Vl 分别与高位代理区和低位代理区起始位置的代码点进行 按位或 运算,得到的结果就是这个处于辅助平面的字符 U+64321 的 UTF-16 编码。

  1. W1 = 0xD800
  2. = 1101 1000 0000 0000
  3. W2 = 0xDC00
  4. = 1101 1100 0000 0000
  5. W1 = W1 | Vh
  6. = 1101 1000 0000 0000
  7. | 01 0101 0000
  8. = 1101 1001 0101 0000
  9. = 0xD950
  10. W2 = W2 | Vl
  11. = 1101 1100 0000 0000
  12. | 11 0010 0001
  13. = 1101 1111 0010 0001
  14. = 0xDF21

4、所以最终 U+64321 这个字符就被编码成了由高位代理和低位代理组成的一个代理对,我们需要同时用 0xD950 和 0xDF21 来表示这个字符。

那么,为什么JavaScript不选择更高级的UTF-16,而用了已经被淘汰的UCS-2呢?

答案很简单:非不想也,是不能也。因为在JavaScript语言出现的时候,还没有UTF-16编码。

由于JavaScript只能处理UCS-2编码,造成所有字符在这门语言中都是2个字节,如果是4个字节的字符,会当作两个双字节的字符处理。

JavaScript的字符函数都受到这一点的影响,无法返回正确结果。

4.3 UTF-8

人们真正需要的是一种节省空间的编码方法,这导致了UTF-8的诞生。UTF-8是一种变长的编码方法,字符长度从1个字节到4个字节不等。

越是常用的字符,字节越短,最前面的128个字符,只使用1个字节表示,与ASCII码完全相同。

编号范围                                 字节
0x0000 - 0x007F        1
0x0080 - 0x07FF        2
0x0800 - 0xFFFF        3
0x010000 - 0x10FFFF      4

五、Java char 和 String 的区别

由于 Java 采用的是 16 位的 Unicode 字符集,即 UTF-16,所以在 Java 中 char 数据类型是定长的,其长度永远只有 16 位,char 数据类型永远只能表示

代码点在 U+0000 ~ U+FFFF 之间的字符,也就是在 BMP 内的字符。

  1. char c1 = '
  2. Java char 和 String 的区别: 字符编码及其存储的更多相关文章

      1. Python第二天 变量 运算符与表达式 input()与raw_input()区别 字符编码 python转义符 字符串格式化 format函数字符串格式化 帮助
      1. Python第二天  变量  运算符与表达式  input()与raw_input()区别  字符编码  python转义符  字符串格式化  format函数字符串格式化  帮助 目录 Pychar ...

      1. 【JavaSE】字符编码和存储编码
      1. 字符编码和存储编码 2019-07-15  22:34:51  by冲冲 1. 英文字母和中文汉字在不同字符集编码下的字节数不同. 英文字母 字节数 : 1; 编码:GB2312 字节数 : 1; 编 ...

      1. char *s="string"和char s[]="string"的区别
      1. char *s="string"的内容是不可以改的 void main() {     char* pStr1 = "Hello!";     char pSt ...

      1. Java web应用中的常见字符编码问题的解决方法
      1. 以下是 Java Web应用的常见编码问题 1. html页面的编码 在web应用中,通常浏览器会根据http header: Content-type的值来决定用什么encoding, 比如遇到Co ...

      1. [转载]Java web应用中的常见字符编码问题的解决方法
      1. 以下是 Java web应用的常见编码问题 1. html页面的编码 在web应用中,通常浏览器会根据http header: Content-type的值来决定用什么encoding, 比如遇到Co ...

      1. const char*、char*、char* const、char[]、string的区别
      1. 1.const char* p: p is a pointer to const char(char const* p 一样)   意思就是不能通过p指针来修改p指向的内容(但是内容可以修改). 2. ...

      1. Char Tools,方便的字符编码转换小工具
      1. 工作关系,常有字符编码转换方面的需要,写了这个小工具 Char Tools是一款方便的字符编码转换小工具,基于.Net Framework 2.0 Winform开发 主要功能 URL编码:URLEn ...

      1. CString、char*与string的区别
      1. 三者的区别 CString 是MFC或者ATL中的实现: string 是C++标准库中的实现: char* 为C编程中最常用的字符串指针,一般以’\0’为结束标志. string和CString均是 ...

      1. 字符编码,存储引擎,MySQL字段类型,MySQL字段约束条件
      1. 字符编码 查看MySQL默认编码命令:\s """ 如果是5.X系列 显示的编码有多种 latin1 gbk 如果是8.X系列 显示的统一是utf8mb4 utf8mb4 ...

    1. 随机推荐

        1. 【Java面试题】37 说出ArrayList,Vector, LinkedList的存储性能和特性
        1. ArrayList和Vector都是使用数组方式存储数据,此 数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插 ...

        1. Linux安装php运行环境
        1. 安装apache: yum install httpd httpd-devel  启动apache: /etc/init.d/httpd start 此时输入服务器的IP地址,应该看到apache的服 ...

        1. Asp.Net实现FORM认证的一些使用技巧(必看篇)
        1. 最近因为项目代码重构需要重新整理用户登录和权限控制的部分,现有的代码大体是参照了.NET的FORM认证,并结合了PORTAL KITS的登录控制,代码比较啰嗦,可维护性比较差.于是有了以下的几个需求( ...

        1. oracle 无效索引
        1. 错误信息:ORA-01502: index 'VOX_ID' or partition of such index is in unusable state 原因:将表的表空间做了更改,导致索引失效. ...

        1. [转]ASP.NET MVC 5 - 查询Details和Delete方法
        1. 在这部分教程中,接下来我们将讨论自动生成的Details和Delete方法. 查询Details和Delete方法 打开Movie控制器并查看Details方法. public ActionResul ...

        1. kafka原理
        1. 今天因为工作接触kafka,先说说kafka是干嘛的. kafka: 说简单点他就是一个基于分布式的消息发布-订阅系统. 然后再理解一些专有名词: Kafka 专用术语 Broker:Kafka 集群 ...

        1. UE4读取脑电波MindWave插件(展示如何使用第三方库制作UE4插件)
        1. MyEEGPlugin.uplugin { , , "VersionName": "1.0", "FriendlyName": " ...

        1. 【转】Go Channels
        1. 转自: http://kdf5000.com/2017/07/16/Go-Channels/ Golang使用Groutine和channels实现了CSP(Communicating Sequent ...

        1. filter IE滤镜(Internet Explorer)CSS
        1. 收集一些IE滤镜,留作之后开发用. 透明度 #myElement { opacity: .; /* other browsers */ filter: progid: DXImageTransform ...

        1. springdata----->spring集成redis(一)
        1. 使用spring-data-redis与redis集成,今天我们就通过例子来学习一下.当时间和耐心都已经变为奢侈,我们只能靠星座了解彼此. spring与redis集成的实例 注意:这里我们测试的是安 ...