美文网首页Linux终极玩家
字节、字符以及字符编码之间的关系

字节、字符以及字符编码之间的关系

作者: 四月不见 | 来源:发表于2022-01-06 00:36 被阅读0次

    一、简介

    可能很多人都有遇到过这样一个问题:“字符与字节有什么区别?”

    其实,字符与字节它们完全是两个不同的的概念,所以两者之间也没有“区别”这一说法。通俗的来说,字节是一种储存数据的单位,而字符则是一些平常我们使用的文字符号(如字母、数字、标点符号)。

    二、字节

    字节(Byte)是计算机信息技术用于计量存储容量的一种计量单位,通常情况下一字节等于有八位,也就是二进制的0000000011111111,所以一个字节(Byte)可区别256(2的8次方)个数字(字符)。

    单位换算规则:

    8bit(位) = 1Byte
    1024Byte = 1KB
    1024KB = 1MB
    1024MB = 1GB
    1024GB = 1TB
    1024TB = 1PB
    1024PB = 1EB
    1024EB = 1ZB
    1024ZB = 1YB
    1024YB = 1BB
    1024BB = 1NB
    1024NB = 1DB

    三、字符编码

    这里先对几个概念做个简单的介绍:
    字符——文字与符号的统称(如字母、数字、标点符号)
    字符集——就是各种字符的集合
    字符编码——就是为字符集中的每一个字符规定一串对应二进制数的一套规则(如在ASCII码中,大写的字母A是01000001)

    字符编码(也称字集码)的种类有非常多,每个国家也会根据自己的文字类型来规定适用的字符编码。

    常见的字符编码有:ASCII、 Unicode、UTF-8、GBK(简、繁体字融于一库)、GB2312(简体中文字符集)、Big5(繁体中文字符集)等。

    1、ASCII 码

    美国根据自己的26个字母,规定了一套共128个字符的编码,叫ASCII码。每个ASCII字符占用1 个字节,而一个字节能够表示256个字符,所以标准的ASCII码只使用了一个字节的后面7位,最前面的1位统一规定为0。

    标准ASCII码包含了33个控制字符(具有某些特殊功能但是无法显示的字符)和95个可显示字符。

    英语用128个符号编码就够了,但是用来表示其他语言,128个符号很多时候是不够的。所以有些国家就把ASCII码字节中闲置的最高位也编入新的符号,这样就可以表示最多256个符号了。我们把利用128--255这一段的叫做扩展ASCII码。

    在 linux 系统中,也可以用如下命令查看ASCII表:

    [nosee@instance-4 ~]$ ascii
    Usage: ascii [-adxohv] [-t] [char-alias...]
       -t = one-line output  -a = vertical format
       -d = Decimal table  -o = octal table  -x = hex table  -b binary table
       -h = This help screen -v = version information
    Prints all aliases of an ASCII character. Args may be chars, C \-escapes,
    English names, ^-escapes, ASCII mnemonics, or numerics in decimal/octal/hex.
    
    Dec Hex    Dec Hex    Dec Hex  Dec Hex  Dec Hex  Dec Hex   Dec Hex   Dec Hex  
      0 00 NUL  16 10 DLE  32 20    48 30 0  64 40 @  80 50 P   96 60 `  112 70 p
      1 01 SOH  17 11 DC1  33 21 !  49 31 1  65 41 A  81 51 Q   97 61 a  113 71 q
      2 02 STX  18 12 DC2  34 22 "  50 32 2  66 42 B  82 52 R   98 62 b  114 72 r
      3 03 ETX  19 13 DC3  35 23 #  51 33 3  67 43 C  83 53 S   99 63 c  115 73 s
      4 04 EOT  20 14 DC4  36 24 $  52 34 4  68 44 D  84 54 T  100 64 d  116 74 t
      5 05 ENQ  21 15 NAK  37 25 %  53 35 5  69 45 E  85 55 U  101 65 e  117 75 u
      6 06 ACK  22 16 SYN  38 26 &  54 36 6  70 46 F  86 56 V  102 66 f  118 76 v
      7 07 BEL  23 17 ETB  39 27 '  55 37 7  71 47 G  87 57 W  103 67 g  119 77 w
      8 08 BS   24 18 CAN  40 28 (  56 38 8  72 48 H  88 58 X  104 68 h  120 78 x
      9 09 HT   25 19 EM   41 29 )  57 39 9  73 49 I  89 59 Y  105 69 i  121 79 y
     10 0A LF   26 1A SUB  42 2A *  58 3A :  74 4A J  90 5A Z  106 6A j  122 7A z
     11 0B VT   27 1B ESC  43 2B +  59 3B ;  75 4B K  91 5B [  107 6B k  123 7B {
     12 0C FF   28 1C FS   44 2C ,  60 3C <  76 4C L  92 5C \  108 6C l  124 7C |
     13 0D CR   29 1D GS   45 2D -  61 3D =  77 4D M  93 5D ]  109 6D m  125 7D }
     14 0E SO   30 1E RS   46 2E .  62 3E >  78 4E N  94 5E ^  110 6E n  126 7E ~
     15 0F SI   31 1F US   47 2F /  63 3F ?  79 4F O  95 5F _  111 6F o  127 7F DEL
    

    2、Unicode 编码

    正如前面所说,字符编码的种类有非常多,同一个二进制数字可以被解释成不同的符号。因此,要想打开一个文本文件,就必须知道它的编码方式,否则用错误的编码方式解读,就会出现乱码。

    可以想象,如果有一种编码,将世界上所有的符号都纳入其中。每一个符号都给予一个独一无二的编码,那么乱码问题就会消失。这就是 Unicode,就像它的名字所表示的,这是一种所有符号的编码,由国际组织设计。所以 Unicode 是一个很大的集合,现在的规模可以容纳100多万个符号,每个符号的编码都不一样。

    需要注意的是,Unicode 只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。比如,汉字的 Unicode 是十六进制数4E25,转换成二进制数足足有15位(100111000100101),也就是说,这个符号的表示至少需要2个字节。表示其他更大的符号,可能需要3个字节或者4个字节,甚至更多。

    所以就会出现两个严重的问题:第一个问题是,如何才能区别 Unicode 和 ASCII ?计算机怎么知道三个字节表示一个符号,而不是分别表示三个符号呢?第二个问题是,我们已经知道,英文字母只用一个字节表示就够了,如果 Unicode 统一规定,每个符号用三个或四个字节表示,那么每个英文字母前都必然有二到三个字节是0,这对于存储来说是极大的浪费,文本文件的大小会因此大出二三倍,这是无法接受的。

    它们造成的结果是:1)出现了 Unicode 的多种存储方式,也就是说有许多种不同的二进制格式,可以用来表示 Unicode。2)Unicode 在很长一段时间内无法推广,直到互联网的出现。

    常见Unicode编码范围:
    -- 汉字:[0x4e00,0x9fa5](或十进制[19968,40869])
    -- 数字:[0x30,0x39](或十进制[48, 57])
    -- 小写字母:[0x61,0x7a](或十进制[97, 122])
    -- 大写字母:[0x41,0x5a](或十进制[65, 90])

    3、UTF-8编码

    UTF-8 就是在互联网上使用最广的一种字符编码,是 Unicode 的实现方式之一。UTF-8 最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。

    如:在UTF-8编码中,一个英文字符占一个字节,一个中文(含繁体)占三个字节;中文标点占三个字节,英文标点占一个字节。

    UTF-8 的编码规则很简单,只有二条:
    1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码(因此对于英语字母,UTF-8 编码和 ASCII 码是一样的)
    2)对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。

    下表总结了编码规则,字母x表示可用编码的位:

    Unicode符号范围      |      UTF-8编码方式
       (十六进制)        |        (二进制)
    --------------------+-----------------------------------
    0000 0000-0000 007F | 0xxxxxxx
    0000 0080-0000 07FF | 110xxxxx 10xxxxxx
    0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
    0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
    

    跟据上表,解读 UTF-8 编码非常简单。如果一个字节的第一位是0,则这个字节单独就是一个字符;如果第一位是1,则连续有多少个1,就表示当前字符占用多少个字节。

    下面,还是以汉字为例,演示如何实现 UTF-8 编码:
    的 Unicode 是4E25100111000100101),根据上表,可以发现4E25处在第三行的范围内(0000 0800 - 0000 FFFF),因此的 UTF-8 编码需要三个字节,即格式是1110xxxx 10xxxxxx 10xxxxxx。然后,从的最后一个二进制位开始,依次从后向前把(100111000100101)填入格式中的x,多出的x位补为0。这样就得到了,严的 UTF-8 编码:11100100 10111000 10100101,转换成十六进制就是E4B8A5

    从上一小节我们看到了中文在Unicode编码的范围为[0x4e00,0x9fa5],然后对应上面的对照表可以看出,这个范围都是处在第三行的,所以可以说“一个中文字符在UTF-8编码中占用了3个字节”。

    UTF8 和 UTF8+BOM 问题:
    什么是BOM? BOM(byte of mark)是一个 Unicode 中一个特殊字符;表示0长度,非断行的空格。
    BOM出现的初衷:BOM最初是用来区分UTF-16和UTF-32的;UTF-16编码使用内容“FE FF”的BOM来标记big ending,即高位结束符;用“FF EE”标记 small ending,即低位结束符。
    微软记事本带来的麻烦:在 UTF-8 文件中放置 BOM 主要是微软的习惯,Windows的记事本有个臭名昭著的破毛病就是在 UTF-8 文件开头加 BOM,在不支持或者未识别utf8编码的环境下,该BOM会被解析成乱码“"”,导致问题。

    其它相关类型:UTF-16(字符用两个字节或四个字节表示)、UTF-32(字符用四个字节表示)

    四、参考

    在线工具:Unicode 字符百科
    什么是Unicode(编码标准)?
    阮一峰的网络日志:ASCII,Unicode 和 UTF-8
    https://home.unicode.org
    字体编辑用中日韩汉字Unicode编码表

    相关文章

      网友评论

        本文标题:字节、字符以及字符编码之间的关系

        本文链接:https://www.haomeiwen.com/subject/teaxcrtx.html