• 一个编码问题


        lua5.3已经支持了utf8编码,也就是说,lua5.3的字符串变量所对应的字节数组是以UTF8编码方式组织的。我写了一个简单的例子,脚本中写入一段中文字符串,然后分别使用lua5.1和lua5.3的解释器打印,看看结果是什么样子的。lua5.1不支持utf8,是按照C的方式来处理字符串的,那么接收中文再打印出来时应该会有一些问题。如下:

    1 print("中华人民共和国")

        但是二者在控制台都完整地输出了原字符串。这个与推理就违背了,那么是什么原因呢?假设程序所在的文本文件是以A方式编码的(如utf8),解释器L读取文本文件拿到字节流,L知道字节流是以A方式编码的,而L中的字符串是以B方式编码的,那么L就要将字节流按A方式解码,并按B重新编码。那么Lua5.1读取后应该是不做任何转换的,作为字符串存储的依然是裸字节流(A方式编码),对其编码方式无任何感知。而输出到控制台时会将裸字节流交予OS,由OS来解释输出。我设想OS是按照GBK或是GB2312的方式来解释输出的,换句话说这里中文字符串也是按GBK或是GB2312来编码的。于是在Lua5.1解释器下输出前三个字节:

    1 print(string.format("%04x", string.byte("中华人民共和国", 1)))
    2 print(string.format("%04x", string.byte("中华人民共和国", 2)))
    3 print(string.format("%04x", string.byte("中华人民共和国", 3)))

        结果为00d6,00d0,00bb。查了GBK编码表(http://www.qqxiuzi.cn/bianma/guobiaoma.php),“中”对应的编码为D6D0,确实是按照GBK之类编码的。如果是这样的话,那么修改编辑器的编码方式,再运行,如果OS还是按照GBK之类来输出的话,那么应该会出问题。于是在Notepad++中修改编码为utf8,运行输出为乱码,而前三个字节则变为了00e4,00b8,00ad,即e4b8ad,正好是“中”的UTF8编码(http://www.mytju.com/classcode/tools/encode_utf8.asp)。

        那么Lua5.3又是如何呢?不幸的是,我是在Centos下测试的,其输出的前三个字节为e4b8ad,与“中”的UTF8编码相符,而中文字符串也能正常地输出。这样看来似乎没有问题了,Lua5.3确实可以读取中文字符串并正确输出。但是Lua5.3在windows下又是如何表现的呢?我编译了Lua5.3的win解释器,运行test.lua(强制以UTF8格式重新编码),其输出竟也与Lua5.1一样,中文乱码,前三个字节为“中”的UTF8编码。这么说来,问题应该在于Centos控制台输出时是默认按照utf8来解释的了,而windows则默认按GBK输出。具体原因暂时不再深究,等下一次再解决。

        这期间又顺便看了JsonFx库在序列化结构体的字符串成员时的处理,将Char转化为utf32的4个字节,以16进制形式拼接在'u'的后面,这样中文就完全以ASCII字符的样子整合在字符串中了:

     1                 int num = 0;
     2                 int length = value.Length;
     3                 this.Writer.Write('"');
     4                 int num2;
     5                 for (int i = num; i < length; i = num2 + 1)
     6                 {
     7                     char c = value[i];
     8                     bool flag2 = c <= 'u001f' || c >= 'u007f' || c == '<' || c == '"' || c == '\';
     9                     if (flag2)
    10                     {
    11                         bool flag3 = i > num;
    12                         if (flag3)
    13                         {
    14                             this.Writer.Write(value.Substring(num, i - num));
    15                         }
    16                         num = i + 1;
    17                         char c2 = c;
    18                         switch (c2)
    19                         {
    20                         case '':
    21                             this.Writer.Write("\b");
    22                             goto IL_192;
    23                         case '	':
    24                             this.Writer.Write("\t");
    25                             goto IL_192;
    26                         case '
    ':
    27                             this.Writer.Write("\n");
    28                             goto IL_192;
    29                         case 'v':
    30                             break;
    31                         case 'f':
    32                             this.Writer.Write("\f");
    33                             goto IL_192;
    34                         case '
    ':
    35                             this.Writer.Write("\r");
    36                             goto IL_192;
    37                         default:
    38                             if (c2 == '"' || c2 == '\')
    39                             {
    40                                 this.Writer.Write('\');
    41                                 this.Writer.Write(c);
    42                                 goto IL_192;
    43                             }
    44                             break;
    45                         }
    46                         this.Writer.Write("\u");
    47                         this.Writer.Write(char.ConvertToUtf32(value, i).ToString("X4"));
    48                     }

        而反序列化过程则相反,拿到u后面4个字节,然后作为Unicode的4个字节转化为对应的Char:

     1     case 'u':
     2     {
     3         int utf;
     4         bool flag = this.index + 4 < this.SourceLength && int.TryParse(this.Source.Substring(this.index + 1, 4), NumberStyles.AllowHexSpecifier, NumberFormatInfo.InvariantInfo, out utf);
     5         if (flag)
     6         {
     7             JsonReader.builder.Append(char.ConvertFromUtf32(utf));
     8             this.index += 4;
     9         }

        搞清楚这些,对于Json使用中碰到的Unicode转化问题,应该就能迎刃而解了。

  • 相关阅读:
    读写INI配置文件
    log4net自动邮件
    C#往SQLServer中插入大数据
    C#反射
    正则表达式
    收发邮件
    读写文本
    Selenium—选择框的相关操作(单选框、多选框、复选框、下拉框)
    Selenium—iframe的操作
    Selenium—web元素的操作
  • 原文地址:https://www.cnblogs.com/Jackie-Snow/p/6814384.html
Copyright © 2020-2023  润新知