zoukankan      html  css  js  c++  java
  • Unicode和UTF-x

    字符集是字符的集合,常见的有:ASCII字符集、GB2312字符集、BIG5字符集、 GB18030字符集、Unicode字符集等

    字符编码则是编码规则,是计算机用于解析字符的规则。常见的有ISO-8859-1,GB2312,GBK,UTF-8,UTF-16等。

    Unicode

    Unicode是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案。用数字0-0x10FFFF来映射这些字符,最多可以容纳1114112个字符。UTF-8、UTF-16、UTF-32都是将数字转换到程序数据的编码方案。

    Unicode的编码空间可以划分为17个平面(plane),每个平面包含65,536个码位。17个平面的码位可表示为从U+xx0000到U+xxFFFF。第一个平面称为基本多语言平面(Basic Multilingual Plane, BMP),或称第零平面(Plane 0),其他平面称为辅助平面(Supplementary Planes)。

    在基本多语言平面内,从U+D800到U+DFFF之间的码位区段是空出来的码位。UTF-16利用这块码位来对辅助平面的字符进行编码。

    UTF-8

    UTF-8是一种可变长度字符编码。

    现在看这样一句话:It's 知乎日报,在Unicode中对应的码和二进制分别是:

    I 0049 00000000 01001001
    t 0074 00000000 01110100
    ' 0027 00000000 00100111
    s 0073 00000000 01110011
      0020 00000000 00100000
    知 77e5 01110111 11100101
    乎 4e4e 01001110 01001110
    日 65e5 01100101 11100101
    报 62a5 01100010 10100101
    

    可以看到,英文的字符前9位都是0,太浪费了,因为utf-8采用了可变长度编码,以8bits为最小变长。编码后如下:

    I 01001001
    t 01110100
    ' 00100111
    s 01110011
      00100000
    知 11100111 10011111 10100101
    乎 11100100 10111001 10001110
    日 11100110 10010111 10100101
    报 11100110 10001010 10100101
    

    它的编码规则是这样的:

    0000〜007F:0XXXXXXX
    0080〜07FF:110XXXXX 10XXXXXX
    0800〜FFFF:1110XXXX 10XXXXXX 10XXXXXX
    10000〜10FFFF:11110XXX 10XXXXXX 10XXXXXX 10XXXXXX
    

    可以看到utf8是一种前缀编码,编码成一个字节的首位为0,编码成两个字节的,第一个字节的前两位为1,编码为三个字节的,第一个字节前三为为1...就是通过这种手段,计算机知道接下来的一个字符包含多少个字节。

    自2009年以来,UTF-8一直是万维网的最主要的编码形式。截止到2019年11月, 在所有网页中,UTF-8编码应用率高达94.3%。第二热门的多字节编码方式Shift JIS和GB 2312分别具有0.3%和0.2%的占有率。几乎所有的互联网联盟都建议采用UTF-8编码。

    结构:

    UTF-8原本使用1-6个字节为每个字符编码,但2003年11月UTF-8被RFC 3629重新规范,只能使用原来Unicode定义的区域,U+0000到U+10FFFF,也就是说最多四个字节。

    • 128个US-ASCII字符只需一个字节编码(Unicode范围由U+0000至U+007F)。
    • 带有附加符号的拉丁文、希腊文、西里尔字母、亚美尼亚语、希伯来文、阿拉伯文、叙利亚文及它拿字母则需要两个字节编码(Unicode范围由U+0080至U+07FF)。
    • 其他基本多文种平面(BMP)中的字符(这包含了大部分常用字,如大部分的汉字)使用三个字节编码(Unicode范围由U+0800至U+FFFF)。
    • 其他极少使用的Unicode 辅助平面的字符使用四字节编码。

    特点

    Ascll码是它的子集,所有英文只需要一个字节,对于欧美地区而言非常的高效且便捷。但中文字符基本都需要三个字节,比较不方便。

    UTF-16

    utf-16也是一种长度的编码,每个字符占用两个字节或者四个字节。

    • 对于基本平面字符,unicode码和utf-16相同,只占用两个字节。

    • 对于辅助平面字符,被编码成一对码元,占用四个字节:

      • 码位减去 0x10000, 则得到 20 bit 长的 0 - 0xFFFFF。
      • 高位的10bit,加上 0xD800 得到第一个码元,又称高位或前导,值的范围是 0xD800...0xDBFF
      • 低位的10bit,加上 0xDC00 得到第二个码元,又称低位或后尾,值的范围是 0xDC00...0xDFFF

      这样设计,那么对于一个两个字节,很容易判断其是基本字符,还是辅助字符,而且很好判断是前导还是后尾。这样每次读取都是连续的 2 字节。

    不同的操作系统对字节顺序的理解不一致。如某字符为十六进制编码4E59,按两个字节拆分为4E和59,在Mac上读取时是从低字节开始,那么会认为此4E59编码为594E,找到的字符为“奎”,而在Windows上从高字节开始读取,则编码为U+4E59的字符为“乙”。此类情况说明UTF-16的编码顺序若不加以人为定义就可能发生混淆,于是在UTF-16编码实现方式中使用了大端序(Big-Endian,简写为UTF-16 BE)、小端序(Little-Endian,简写为UTF-16 LE)的概念,以确保不同的字节序也能呈现相同内容,目前Windows和Linux默认使用UTF-16 LE。

    utf-8 和 utf-16 如何选择

    utf-16的特点是编码规整,每个字符都是两字节或者四字节。日常使用的字符几乎都是两字节,32位的机器一次访问读取的是两个完整的字符,而如果使用utf-8,有的字符是三字节,就没这么方便了。因此主要考虑内存读写效率时,采用utf-16。

    但是utf-16对于ascll码字符存在空间浪费,而多数时候ascll码字符更多,因此在网络或者存储时,普遍采用utf-8.

    另外,对于cjk(中日韩文字)编码时,很多字符都是在于基本平面内,使用 utf-16 只需要两字节,而使用 utf-8 通常需要 3 字节。也就是说,在cjk文字偏多时,采用utf-16更加有空间优势。

    • Java的编码格式是什么?

      java的编码格式要分情况来看,在类文件中编码默认是 utf-8(可以设置其他编码),因为类文件基本都是ascall字符,编码成utf-8最省空间;而在 jvm 运行时,即在内存中,会统一转换为 utf-16。原因就是 utf-16 方便 cpu 读写,而utf-8对于ascll字符多的情况下更省内存。

    UTF-32

    utf-32是定长的编码,每个码位使用四个字节进行编码。优点是和unicode一一对应,缺点是太浪费空间。

    参考:

    https://zh.wikipedia.org/wiki/Unicode

    https://zh.wikipedia.org/wiki/UTF-8

    https://zh.wikipedia.org/wiki/UTF-16

    https://www.jb51.net/article/81416.htm

    https://www.zhihu.com/question/308677093

  • 相关阅读:
    关于类型转换构造函数的疑惑点
    类模板与静态 成员变量
    模板与友元
    类模板与派生
    类模板
    函数模板
    泛型程序设计基本概念
    3、成员函数
    条款 06:若不想使用编译器自动生成的函数,就该明确拒绝
    PHP操作redis
  • 原文地址:https://www.cnblogs.com/cpcpp/p/15367065.html
Copyright © 2011-2022 走看看