• 若干编码说明


    一、gb2312
    现在我们大部分的中国程序员编译的程序可执行代码中包含的都是gb2312编码,这些编码通常体现在代码中的字符串里。编译器对于这些字符串的内容并不做特殊解释,因为gb2312中的常用英文字符是和ASCII码兼容的。
    根据编码的约定,通常的前32个字符是作为控制字符,也就是无法在屏幕上直接对应一个可显示的字符,它们的范围在0x00-0x20之间,再往上的0x20到0x7f通常认为是可显示的字符。共96个字符,但是汉字编码中对于这个区间的第一个和最后一个都没有使用,也就是合法区间是从0x21--0xFE,共94个字符。大家可以看到,此时的ascii编码只是用了8个字节中的7个,0x80以上的没有在ascii码中定义,此时不同的编码就会对这些内容进行解释。
    和低128编码大致分区类似,此时的0x80开始到0xA0依然作为非显示的控制字符使用,剩余的96个作为显示字符。gb2312编码时就使用了这些0xA)开始的编码,只是它们是由两个连续的字节组成一个汉字。这是ascii码的编码规则,而对于汉字来说,它的划分更偏重于逻辑的划分,它只是简单的将这些汉字划分为不同的区,每个区总共94个汉字。当用内码表示一个汉字时,只需将其区位编码和区内编码各自加上0xA0即可。它的优点是可以和ascii编码完全兼容。
    二、utf-8编码
    unicode编码的时候和IPV4到IPV6的扩展一样,使用了足够大的空间,优点是可以表示所有的字符,但是缺点就是对于ascii码,它存在大量的0字节,这些字节无论对存储还是传输来说都是极大的浪费,所以此时有了utf-8编码,它存在的意义同样是为了兼容ascii码编码不变,从而满足大部分英语语系国家的传输。
    这个编码使用的是非常简单的前缀码编码格式,它通过开始的1的个数来确定自己包含的真正有效负载数量,并且保证不同的负载可以互相区分。
    wiki中对于该编码的说明

    Unicode和UTF-8之间的转换关系表
    UCS-4编码    UTF-8字节流
    U+00000000 – U+0000007F    0xxxxxxx
    U+00000080 – U+000007FF    110xxxxx 10xxxxxx
    U+00000800 – U+0000FFFF    1110xxxx 10xxxxxx 10xxxxxx
    U+00010000 – U+001FFFFF    11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
    U+00200000 – U+03FFFFFF    111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
    U+04000000 – U+7FFFFFFF    1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
    可以看到,它完全兼容了ascii码,所有的编码最高位都不是零,从而区分了unicode的字符和常规ascii编码。第一个字节可以确定之后字节的长度,并且和ascii码(0开始字符)、中间码(10开始字符)均没有重合。
    三、不同编码之间的转换
    通常的文件并不在意字符的编码,但是在显示的过程中可能需要进行特殊的转换,这些转换在linux系统中通过一组iconv函数完成,基本的接口为iconv_open、iconv和iconv_close,这的确是一个经典的三元组组合,它们和正则表达式的三个基本操作语义相同。
    这组转换和内核没有关系,C库完全可以独立完成,我们通过
    strace iconv --list
    可以大致知道这个库文件保存在
    [root@Harry thiscast]# ll /usr/lib/gconv/
    total 6264
    -rwxr-xr-x. 1 root root  19840 2010-10-23 02:07 ANSI_X3.110.so
    -rwxr-xr-x. 1 root root  11440 2010-10-23 02:07 ARMSCII-8.so
    -rwxr-xr-x. 1 root root  11488 2010-10-23 02:07 ASMO_449.so

    文件夹,其中有一个不同字符集合之间转换的配置文件gconv-modules,其中定义了可以转换的文件以及大量转换的so,它们这些so中一般包含了转换的函数和转换时映射的字库数据库,上层的iconv接口会通过特定的结构找到这些so中的函数并将用户输入的编码转换为目标格式编码。
    四、glibc中相关实现
    glibc-2.7iconv文件中包含了iconv函数族实现及其它功能性代码,其它数据库性质的文件则保存在glibc-2.7iconvdata文件夹下。这个转换的过程应该是由makefile完成,但是现在没有兴趣和时间来分析它的实现。但是可以摘录一下其中的一些片段glibc-2.7iconvdatagb2312.c:

    /* The conversion table to UCS4 has almost no holes.  It can be generated with:

       egrep '^0x' /mnt/cdrom/unix/mappings/eastasia/gb/gb2312.txt |
       perl tab.pl

       where tab.pl is:
       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       $n=0;
       while (<>) {
         local($gb, $ucs4, %rest) = split;
         local($u)=hex($ucs4);
         local($g)=hex($gb);
         printf (" ") if ($n % 4 eq 0);
         ++$n;
         printf (" [0x%04x] = 0x%04x,",
                 int(($g - 0x2121) / 256) * 94 + (($g - 0x2121) & 0xff), $u);
       }
       printf (" ");
       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     */
    const uint16_t __gb2312_to_ucs[] =
    {
      [0x0000] = 0x3000, [0x0001] = 0x3001, [0x0002] = 0x3002, [0x0003] = 0x30fb,
      [0x0004] = 0x02c9, [0x0005] = 0x02c7, [0x0006] = 0x00a8, [0x0007] = 0x3003,
      [0x0008] = 0x3005, [0x0009] = 0x2015, [0x000a] = 0xff5e, [0x000b] = 0x2016,
      [0x000c] = 0x2026, [0x000d] = 0x2018, [0x000e] = 0x2019, [0x000f] = 0x201c,
      [0x0010] = 0x201d, [0x0011] = 0x3014, [0x0012] = 0x3015, [0x0013] = 0x3008,
      [0x0014] = 0x3009, [0x0015] = 0x300a, [0x0016] = 0x300b, [0x0017] = 0x300c,
      [0x0018] = 0x300d, [0x0019] = 0x300e, [0x001a] = 0x300f, [0x001b] = 0x3016,
      [0x001c] = 0x3017, [0x001d] = 0x3010, [0x001e] = 0x3011, [0x001f] = 0x00b1,
      [0x0020] = 0x00d7, [0x0021] = 0x00f7, [0x0022] = 0x2236, [0x0023] = 0x2227,
      [0x0024] = 0x2228, [0x0025] = 0x2211, [0x0026] = 0x220f, [0x0027] = 0x222a,
      [0x0028] = 0x2229, [0x0029] = 0x2208, [0x002a] = 0x2237, [0x002b] = 0x221a,
      [0x002c] = 0x22a5, [0x002d] = 0x2225, [0x002e] = 0x2220, [0x002f] = 0x2312,
      [0x0030] = 0x2299, [0x0031] = 0x222b, [0x0032] = 0x222e, [0x0033] = 0x2261,
      [0x0034] = 0x224c, [0x0035] = 0x2248, [0x0036] = 0x223d, [0x0037] = 0x221d,
      [0x0038] = 0x2260, [0x0039] = 0x226e, [0x003a] = 0x226f, [0x003b] = 0x2264,
      [0x003c] = 0x2265, [0x003d] = 0x221e, [0x003e] = 0x2235, [0x003f] = 0x2234,
      [0x0040] = 0x2642, [0x0041] = 0x2640, [0x0042] = 0x00b0, [0x0043] = 0x2032,
      [0x0044] = 0x2033, [0x0045] = 0x2103, [0x0046] = 0xff04, [0x0047] = 0x00a4,
      [0x0048] = 0xffe0, [0x0049] = 0xffe1, [0x004a] = 0x2030, [0x004b] = 0x00a7,
      [0x004c] = 0x2116, [0x004d] = 0x2606, [0x004e] = 0x2605, [0x004f] = 0x25cb,
      [0x0050] = 0x25cf, [0x0051] = 0x25ce, [0x0052] = 0x25c7, [0x0053] = 0x25c6,
      [0x0054] = 0x25a1, [0x0055] = 0x25a0, [0x0056] = 0x25b3, [0x0057] = 0x25b2,
      [0x0058] = 0x203b, [0x0059] = 0x2192, [0x005a] = 0x2190, [0x005b] = 0x2191,
      [0x005c] = 0x2193, [0x005d] = 0x3013, [0x006e] = 0x2488, [0x006f] = 0x2489,
      [0x0070] = 0x248a, [0x0071] = 0x248b, [0x0072] = 0x248c, [0x0073] = 0x248d,
      [0x0074] = 0x248e, [0x0075] = 0x248f, [0x0076] = 0x2490, [0x0077] = 0x2491,
      [0x0078] = 0x2492, [0x0079] = 0x2493, [0x007a] = 0x2494, [0x007b] = 0x2495,
      [0x007c] = 0x2496, [0x007d] = 0x2497, [0x007e] = 0x2498, [0x007f] = 0x2499,
      [0x0080] = 0x249a, [0x0081] = 0x249b, [0x0082] = 0x2474, [0x0083] = 0x2475,

  • 相关阅读:
    vscode安装
    Linux下 Python绘图与可视化 及matplotlib与_tkinter安装
    C语言-结构体定义的几种方式
    leetcode- 88. 合并两个有序数组
    leetcode-16. 最接近的三数之和
    Leetcode-15. 三数之和
    Leetcode-561. 数组拆分 I
    Windows_pycharm下安装numpy
    python实现两个两个的翻转字符串
    linux复制文件夹、重命名文件夹、删除文件夹
  • 原文地址:https://www.cnblogs.com/tsecer/p/10487475.html
Copyright © 2020-2023  润新知