/ 技术

关于字符编码

以下内容纯个人理解,如有遗漏/错误等我反应过来再补充吧~

(感觉还是用类似Q&A的方式来写写比较好)

什么是字符?

在计算机里面,无意义的二进制0和1(如果不知道的话,继续看下去也没什么意义了。。。),按照特定的长度可以表示一个数值(例如二进制的1000表示十进制的8);对于不同的数值,如果有一个table来映射(有没有密码本的赶脚),那不同的数值就可以表示特定的含义 --- 字符。

例如,二进制里面的01000001

  • 十进制(也理解成表的话,只是“映射”方式更简单)就是65
  • ASCII表里,对应的是英文大写字母A

你看,同一个数值,通过不同的table,就有了不同的含义(小马过河的即视感。。。)。

什么是字符编码?

很显然,ASCII这个表能表示的含义太少了(只有128个,而且其中还有33个不能显示的字符),尽管用来表示英文(A-Z + a-z + 一些常用符号)是足够了,但你让其他语言怎么看?

所以不同的国家,就有了各自的一张Table;这些Tables,就统称为ANSI编码。所以一般说ANSI编码,不是单指简体中文的GB2312或者日文的JIS,而是指这个合集,指这种“每个国家都不同但又是各自国家标准的编码表”。

一个国家一张表?

一个国家一张表,听起来不错,但有个问题在于 ---- 这意味着,同一个数值,在不同国家表示的含义就不同了啊啊啊!

例如十六进制的0xD2BB这样两个字节:

  • GB2312中表示大写数字
  • JIS中表示メサ (不好意思我不知道这是啥意思。。。)

所以这就意味着,同一份文档,在不同国家,可能会出现显示内容完全不同的情况(一般情况下是乱码。。)

尤其是在大互联网浪潮下,这意味着,在本国打开一切OK的网页,在国外打开就是一团浆糊了:

(哈哈,其实本站不是ANSI编码,这里强制使用ANSIJIS以后~ 就呵呵了~ )

乱码怎么办?

怎么办?两种办法:

  1. 一种是找一个标准,大家统一使用,也就是目前渐成主流的Unicode编码;

  2. 再一种就是自动转换编码,例如你在大天朝,一般是用GB2312(简体中文)编码,那么如果想看一篇使用JIS编码的文章/网页,就需要你使用的阅读器/浏览器做两件事情:

    1. 自动编码识别 -- 让阅读器/浏览器知道这篇文章/网页是JIS编码的
    2. 编码转换 -- 将JIS编码转换成GB2312编码(当然也可以在阅读器/浏览器内部,直接用JIS编码来显示)
什么是Unicode?

更具体的请Wiki

简单来说,就是把不同的语言,按照特定的顺序,不重复的排列下去。组成一个巨大的“字典”(这也意味着这个字典的页数要够大)。

重点就是不重复

具体的可以看这里[Wiki]

有一点需要注意的是,Unicode是统称。

UTF-8/UTF-16/UTF-32等等,都是Unicode

UTF-8就是为了存储和传输方便,缩小版的UTF-16

显然的是,它们可以相互转换(不是查表,而是用公式)。

为什么需要自动编码识别?

因为,很多情况下,目标文档的编码是未知的。

举个例子,这就好像古时候密码破译的场景,同一个密码,用不同的密码本对照破译,有可能会得到完全相反的含义。所以如何正确识别编码,就变得特别重要。

那文档没有特定“编码识别符”么?

对,没有统一标准(即使是Unicode)。或者说没有“强制”执行的标准,来约定必须在文档某个位置标注当前文档编码类型的。

这也就意味着 -- 自动编码识别必不可少。

如何自动编码识别?

很多算法,一句话就是“模式识别”。

举个例子,在中文里,一般会有一些出现频率较高的词,如“的、我”等等;不同的语言,常用词也显然是不一样的(当然可能存在特例,中文的“的”和日文的“的”都是高频词且十六进制数值一样(仅举例,显然不一样嘛),但就目前的统计数据而言,大部分高频词都一样的可能性几乎为0),所以算法基本如下:

  1. 读取文档的一段内容(例如前4096字节),当然也可以全部读取
  2. 统计这段内容中对不同编码的高频词的命中率
  3. 命中率最高者即为“猜”到的编码

就是这么简单。

自动编码识别就这么简单?

是也不是,人脸识别算法也很简单,但想做好,就很难。

同理。

所有“模式识别”算法,都不可避免面对一个识别率的问题。

想要越高的识别率,就意味着越复杂的算法,越精细的参考点,换言之,越多的if...else

自动编码识别也一样。

当采样太少时(例如整个文本就10字节),识别率会降低(降到很低)。

当样本库太多时,误判率会升高。

这就是难点:如何增加可识别的编码,同时提升识别率。

主流的自动编码识别开源代码有哪些?

jchardet,Mozilla用在Firefox里用的自动编码识别库。

cpdetector,jchardet就基于它。

多年前,在此基础上做了一些优化(最主要的是优化识别率),已整理到Github上 -- CharsetDetector

编码识别完以后如何编码转换?

找一个编码转换库,大声说“请把这段数据,从编码A转换到编码B”。

回答完毕。

其实简单来说,这类似查汉译英字典的过程。

而编码转换,其实就是若干大字典之间互查。

有哪些编码转换库?

最有名的应该就是ICU(不是急症病房)

其实我这么说是因为我也只用过这个。。。

原因是:Android原生支持ICU。换言之,Java也好,JNI也好,都可以直接使用ICU的接口来进行编码转换。


基本就这些了,结果我手贱搜到了一篇《字符,字节和编码》 。。。 写的好浅显易懂啊。。。妈蛋。。。匿了。。。