简体 “” iconv("GBK", "UTF-8") 失败

来源:互联网 发布:厦门淘宝美工培训学费 编辑:程序博客网 时间:2024/05/19 03:17

1.首先总结几个概念:

  • Unicode是全球最全的字符格式。iconv 源代码里面所有转化都是先将原格式转成”UCS-4”(用四个字节来表达UNICODE的格式),然后在转成目标格式。 绝大多数字符的UNICODE码都是2字节的,UCS-2就够了,iconv为了作为中间格式选择为4字节,不足4字节的高位都是0。下面是iconv的定义代码:
/* Our own notion of wide character, as UCS-4, according to ISO-10646-1. */typedef unsigned int ucs4_t;
  • UTF-8 是Unicode的一种存储实现方式,编码就是UNICODE码。因为 UCS-4比较浪费空间。比如:UTF-8就是把一个Unicode编码按照规则把bit位 拆开后,存到变长的mb 字符串中具体原则也非常简单。详细规则就不说了,很容易搜到。 通常汉字的UTF-8是三个字节。所以可以说 UTF-8跟UCS 没有本质区别。UTF-16在表达两个字节的UNICODE是就跟UCS-2是相同的。

  • GB2312,GBK, GB18030都是中文字符集,按时间发展来的。
    按照集合的大小来分类,可以简单粗暴地概括为:GB2312 < GBK < GB18030
    GBK经过几次扩容,但是很多字符还是没地方放了,于是就放在PUA(用户使用)里。

  • CP936是微软定义的字符格式,可以认为跟GBK是相同的,当然网上说有几个字符是有细微差别的,通常基本上可以忽略,而且Iconv里面CP936转其他的时候会先尝试用GBK,失败了再去用CP936. 可以认为CP936是GBK的最新扩展集合的扩展集合。但是跟GB18030 还是不一样的。
  • 可以说在windows的系统里 GBK = CP936 = ANSI(系统会自动判断英文存ANSIC,中文存CP936)。这个用UE也可以看到选项就是:936 (ANSI/OEM -简体中文 GBK)

下面说我的问题:
- 经过测试:
繁体 “鶄” iconv(“GBK”, “UCS-2BE”) , iconv(“GBK”, “UNICODEBIG”) 结果都是对的 849D (左边是高地址,注意Utrl—Edit显示是左边低地址)
简体 “” iconv(“GBK”, “UCS-2BE”) ,iconv(“CP936”, “UCS-2BE”) 都失败。
原因是:
GBK增补的80个字符本来是放在Unicode PUA区的,后来又被新版 Unicode收录。所以既可以用PUA区的编码表示,也可以用非PUA编码表示。 具体参考:
http://www.fmddlmyy.cn/text24.html

  • 实际上:简体 “” 是有两个Unicode编码的 PUA: E85F 非PUA:4D16.
    问题根本原因是:window和linux对这个字的所采用Unicode解析方式不同。
  • 在window记事本另存为UTF-16的时候就是E85F,换言之window用CP936来处理这个字符,把这个字符当成GBK的一种,直接转到 Unicode的 PUA来显示。估计微软当年遇到了这个问题,他不想废弃CP936,就对这些些字符进行了定制化处理。
  • 而在Linux上 的字符处理是依赖于iconv。iconv认为该字符不是GBK也不是GBK扩展,而是GB18030. linux对 PUA码也不做处理,已经挪为他用。
  • 这点可以通过 在linux系统用文本文件存储”” 字,然后查看的utf-8 编码跟windos下 不一样来证明。
  • windows保存的UTF8格式的TXT放在linux下面显示成为 “草字头下面加然字”。linux下的UTF8编码是: E4B496 对应 Unicode为 “4D16” 这个新版Unicode的编码。

【最终结论】 用GB18030 替代 GBK在incov中使用,不再使用GBK。
如: iconv(“GB18030”, “UTF-8”)

0 0