0%

有关字符集与编码

当我在解决Linux下解压zip文件的问题时发现编码方面的问题还蛮多的, 在此记录.

Windows下编码方式的坑

🔗 知乎-Windows记事本的ANSI, Unicode, UTF-8这三种编码模式有什么区别?

🔗 「带 BOM 的 UTF-8」和「无 BOM 的 UTF-8」有什么区别?网页代码一般使用哪个

总结一下, 在Windows中:

  • 所谓的「ANSI」指的是对应当前系统 locale 的遗留(legacy)编码
  • 所谓的「Unicode」指的是带有 BOM 的小端序 UTF-16
  • 所谓的「UTF-8」指的是带 BOM 的 UTF-8

之前一直听说Windows自带的记事本不要用, 会自动在文件开头加一个东西, 导致一些地方显示该文件开头有一个 "?" , 一直不知道是多了个啥, 原来是UTF-8/UTF-16编码的文件会在文件开头多一个 BOM. UTF-8与带BOM的UTF-8的区别在于带BOM的UTF-8文件开头有U+FEFF. 微软使用带BOM的UTF-8 的目的是将UTF-8与ASCII等编码方式区分开, 但这就导致了在很多时候UTF-8默认是不带BOM时文件读取有误.

GBK不是一种编码格式

GBK并不是一种编码格式, 而是一个字符集. 我觉得很low的是GBK的全称是 Guojia Biaozhun Kuozhan 🤦‍ 不过也可以理解, 毕竟这三个字母是从"国标扩"的首拼发展来的.

自整理的中文字符集发展史

以下是我整理的中文字符集发展史:

  • 最开始中国国家标准化管理委员会发布了 GB/T2312-1980 (GB国标首拼, T, 指推广, 非强制性的标准), 包括了6763个常用汉字, 发布以后许多有汉字的语言也采用了这个字符集. 但这个字符集很不够, 缺少很多生僻字, 繁体字, 对日本, 韩国汉字收录也很不全.
  • 微软根据GB2312做出了cp936 (code page936), 字符集方案为GB2312, 编码方案为 EUC-CN.
  • 1993年Unicode1.1发布后国标委抄过来发布了GB 13000.1-1993.
  • 这时微软利用cp936中收录GB2312-1980后未使用完的码位收录了GB13000.1-1993的全部字符, 这样既兼容了GB2312又添加了许多字符. 这个新版本cp936最早实现于Windows95简体中文版. 这之后微软又陆陆续续给cp936加了几个字符. 直到2002年IANA将cp936的字符集注册为GBK. GBK共收录21886个汉字和图形符号.
  • 再后来因为字符还是不全 (比如emoji什么的)以及其他原因发布了GB 18030-2000, 在 Windows的对应代码页为cp54936. 但值得一提的是尽管2000年就有了新标准, 但Windows系统的系统语言为简体中文时的默认代码页仍为cp936. 原因可以参考这里. 文章大意: 微软划水, 国家也没上心.
  • 最近的一版标准字符集是GB 18030-2005. 但这个好像有点复杂, 我并没有太看懂, 反正和之前的几个标准很不同. 怎么个不一样可以参考这里.

Unicode与UTF-8是不同层面的东西

我曾经以为Unicode是一种编码格式, 就像UTF-8是一种编码格式, 但后来我发现这两者根本是不同层面上的东西.

Unicode与UCS

两者关系

Unicode (统一码) 同一层面的概念是UCS (Universal Character Set, 通用字符集). UCS和Unicode分别由ISO (国际标准化组织) 和一帮软件制造商 (Xerox, 苹果等成立了个统一码联盟) 先后发起. 后来他们才合并工作. 实际上两者是差不多的玩意. 我并不相信统一码联盟在成立时不知道ISO已经在开发UCS了 (UCS项目启动比Unicode早4年), 而在这样的情况下还要开发Unicode, 个人认为是商业原因. 直到现在这仍然是两个独立的项目, 但项目进度同步且两个组织都宣称要和对方保持兼容. 个人觉得很蠢🤷‍

两者差异

硬要说的话其实Unicode与UCS有一些细节不同.

比如ISO/IEC 10646-1使用四种不同风格的变体来显示简体中文, 繁体中文, 日语, 韩语汉字, 但Unicode2.0中只有简体中文的变体. 因此有过日本人无法接受Unicode的说法. (现在应该是没这问题了)

应该还有小区别吧? 其他区别我不知道, 也懒得找了😁

现代编码模型

Unicode是一套有些复杂的编码系统, 并不是单纯一个字符集方案或是一个编码方案, 而是构建出了一个 现代编码模型. (这段话对UCS同理)

这个模型分五层:

  • 抽象字符集(Abstract character repertoire)
  • 编码字符集(Coded Character Set)
  • 字符编码方式(Character Encoding Form)
  • 字符编码方案(Character Encoding Scheme)
  • 传输编码语法(Transfer Encoding Syntax)

按我的理解: 抽象字符集是一个抽象字符的集合, 不关注字形, 更关注字意. 比如钟和鐘的抽象字符是同一个, 而编码字符集是一个映射, 规定把一个抽象字符映射到哪个字符平面, 哪个码点. 但这并不是一一映射, 为了兼容或者有的字 (比如CJK字) 可能有多个变体. 字符编码方式又称为"storage format", 我猜这是因为这一层将码点编码成码元(这里的编码方式就是Unicode Transformation Format, 包括UTF-8, UTF-16, UTF-32等方法, 也有GBK, Big5等), 而码元正是每次从文件中读取到的字符的格式.

Unicode编码模型详细阐述可以参考这里

感谢您的认可!