1+1=10

记记笔记,放松一下...

混乱的字符集编码

ASCII,Latin1,GBK,Utf8,... 字符集编码,乍一听似乎是一个简单的东西,但它却隐藏着丰富的历史故事(乱)和复杂的技术细节(杂)..., 不妨抛开细节和完整性,简单写写

从Python开始?

都2025年了,尽管 C++引入了一个又一个字符类型 ,但即便是在最简单的UTF-8编码上,C++仍在苦苦挣扎

所以我们还是从Python3开始吧,毕竟和C/C++,甚至是Python2相比,它非常简单,不是么?

初识 Python 内置编码

不考虑别名的话,Python也支持将近百种编码,可以列个表格(本文重点关注标红和标绿的部分):

codec

尽管看起来还是很杂,但上面表格已经做了很多简化。比如,表中ascii只列出2个别名,其实在Python下,单单一个ascii,有如下一堆别名:

  • 646
  • ansi_x3.4_1968
  • ansi_x3.4_1986
  • ansi_x3_4_1968
  • cp367
  • csascii
  • ibm367
  • iso646_us
  • iso_646.irv_1991
  • iso_ir_6
  • us
  • us_ascii

获取编码名

要获得python内置的完整的编码列表,可通过如下python代码输出:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import encodings

aliases = encodings.aliases.aliases

codec_map = {}
for alias, main_name in aliases.items():
    codec_map.setdefault(main_name, []).append(alias)

# 按编码名字排序并输出
print(f"{'编码':<20}{'别名'}")
print("-" * 50)
for main_name, alias_list in sorted(codec_map.items()):
    aliases_str = ", ".join(sorted(alias_list))
    print(f"{main_name:<20}{aliases_str}")

太多了,怎么看?

按时间先后看看,挑几个关键节点看看??

EBCDIC 编码(8bit),1963

在 ASCII 之前,已经存在 EBCDIC 编码,但是EBCDIC 是 IBM 的专有编码,不是开放标准。

  • BCD:全称 Binary Coded Decimal(二进制编码十进制),起源于1940年代
  • EBCDIC:全称 Extended Binary Coded Decimal Interchange Code(扩展二进制编码十进制交换码),1963年,IBM推出基于BCD的扩展,主要用于IBM大型机。

EBCDIC 有超过186种变体(代码页)。前面表格中出现的,以下编码,属于 EBCDIC 的变种:

  • CP037
  • CP424
  • CP500
  • CP875
  • CP1026
  • CP1140

ASCII 标准诞生(7bit),1967

ASCII,发音 /ˈæskiː/

随着个人计算机(PC)的普及,ASCII 成为跨平台的通用编码。而由于 ASCII 与 EBCDIC 不兼容,ASCII 的普及也推动了 EBCDIC 的边缘化。

  • ASCII:全称 American Standard Code for Information Interchange,1967年,由 ANSI(美国国家标准协会),作为行业标准发布。

不过 ASCII ,只有7bit,容量实在太小了,只能照顾到美国,连英国可能都不舒服(英镑符号 £ 在哪里?)

ASCII 扩展:商业公司

ASCII只使用7bit,把高位置一,还可以多存储128个字符。多出来的这部分,到底存法语字符呢,存葡萄牙语字符呢,还是阿拉伯语字符呢?

分而治之,分别用不同的代码页(code page)不就得了。于是

IBMxxx 扩展

IBM 整出了下面一堆和ASCII兼容的东西:

  • cp437 / IBM437
  • cp850 / IBM850
  • cp852 / IBM852
  • cp855 / IBM855
  • cp857 / IBM857
  • cp858 / IBM858
  • cp860 / IBM860
  • cp861 / IBM861
  • cp862 / IBM862
  • cp863 / IBM863
  • cp864 / IBM864
  • cp865 / IBM865
  • cp866 / IBM866
  • cp869 / IBM869
  • ...

Apple 扩展

苹果公司闲不住,有如下东西:

  • mac_cyrillic
  • mac_greek
  • mac_iceland
  • mac_latin2
  • mac_roman
  • mac_turkish

ASCII 扩展:ISO 8859 系列标准

在 1987 年,国际标准化组织(ISO)发布了一组针对 8 位 ASCII 扩展的标准,即 ISO 8859 系列。

注意:与其他编码相比,ISO 8859 将 8016 到 9F16(十六进制)这 32 个字符位置保留为控制字符。

该系列中,最流行的是

  • ISO 8859-1(ISO Latin 1),它包含了大多数常见西欧语言字符。
  • ISO 8859-15(ISO Latin 9),是 Latin1 的改进版,使用欧元符号 € 等取代了Latin 1中的一些不常用的字符。

一共15个标准:

  • ISO 8859-1 to 11
  • ISO 8859-13 to 16

其中:ISO 8859-12 从未被正式分配,直接被跳过了。

ISO-8859-1 扩展:Windows-1252

Windows-1252 也被称为 CP1252、Windows Latin 1 甚至是 ANSI。它支持大部分的 西欧语言,包括英语、法语、德语、西班牙语、意大利语、葡萄牙语、荷兰语、丹麦语、瑞典语、挪威语等。

尽管和 Latin-1(ISO 8859-1)非常相似,但是并不相同,它在ISO 8859 的保留区里面,塞了很多其他字符,比如 欧元符号 €。

曾经的辉煌:

  • Windows-1252 是Windows默认的编码之一,特别是在早期的 Microsoft Office 文档(如 Word 和 Excel)中。
  • 在 HTML 和网页开发中,Windows-1252 曾被广泛使用,特别是在西欧语言网站中。
  • 在未指定编码的情况下,许多早期的浏览器(如 Internet Explorer)会默认使用 Windows-1252。

HTML5 的妥协:将 ISO-8859-1 视为 Windows-1252

在 HTML5 标准中,如果在网页中声明了字符编码为 ISO-8859-1,浏览器会将其解释为 Windows-1252,而不是严格意义上的 ISO 8859-1。

这种行为是为了保证向后兼容,因为早期大量网页实际使用的是 Windows-1252,而不是 ISO 8859-1。

Windows-125x 字符集

Microsoft 定义了一系列 Windows-125x 字符集,用于支持不同语言和地区的文本编码。这些字符集都是基于 单字节编码,每个字符占用 1 个字节,最多支持 256 个字符。

这一系列可以和 ISO-8859 系列进行对应。二者的根本区别和 前面 ISO-8859-1 与 Windows 1252 的区别一样。

特性 Windows-125x ISO-8859 系列
范围 0x00-0xFF 0x00-0xFF
差异 0x80-0x9F 区域是可打印字符 0x80-0x9F 区域是控制字符
使用场景 Windows 系统 早期的 UNIX 和网络协议

中文编码:GB2312、GBK、GB18030

ISO-8859 基本解决了除了中国、日本、韩国之外,其他国家的编码问题。但是一个8位字节,铁定无法解决中日韩字符编码

GB2312:区位码

GB2312 是中国国家标准化管理委员会于 1980 年发布的一种字符集标准,全称是 《信息交换用汉字编码字符集·基本集》。它是中国最早的用于计算机处理简体汉字的编码标准之一,主要用于简体中文的显示和处理。

  • GB2312 将所有字符划分为 94 个区,每区包含 94 个字符。
  • 区号和位号的范围均为 01-94。
  • 每个字符的位置由 区号 和 位号 唯一确定。

为了与 ASCII 兼容:用于计算机编码时,区位码会加上一个偏移量 0xA0 转化为机内码

GBK

1993年,Unicode 1.1 标准发布。

同年,GBK开始定义。

GBK(汉字内码扩展规范)是对 GB2312 的扩展,兼容 GB2312 的所有字符,同时新增了 21003 个汉字(对应于Unicode 1.1 引入的汉字),包括繁体字、更多生僻字和少数民族语言字符。

微软的代码页 CP936 基本可以认为对应 GBK。

GB18030

GB18030 是中国国家标准,支持所有 Unicode 字符,是中文字符编码的最新标准。

GB2312 和 GBK 都是 GB18030 的子集。

中文编码:Big5、Big5-HKSCS

Big5 是一种用于繁体中文字符的编码标准,最早由台湾的五家厂商(因此得名 Big5)在 1984 年共同制定。它是繁体中文计算机系统中最广泛使用的字符集之一,尤其在台湾和香港地区应用广泛。

作为一种双字节编码方案,Big5 设计上与 GB2312 类似,但它专注于繁体中文的字符集。

初版 Big5 的字符集有限,无法覆盖所有繁体中文字符以及其他扩展需求。后续版本增加了一些扩展字符集,例如:

  • Big5+:新增字符以支持更多的生僻字和罕见字符。
  • Big5-HKSCS(香港增补字符集):为香港特别行政区设计的扩展版本,增加了约 5000 个字符,用于处理香港地区的独特用字。

ISO-2022-CN

前述各个字符集之间缺乏统一性,导致跨语言和跨系统的文本交换变得困难。因此,ISO 2022 的诞生旨在提供一种灵活的机制,允许在同一数据流中动态切换字符集,以支持多语言环境。

  • 1971 年:首次发布 ISO 2022,成为早期字符编码标准的基础,用于多语言文本支持。
  • 1986 年:进行了修订,逐步完善了字符集切换的机制,支持更多的字符集。
  • 1994 年:被重新编号为 ISO/IEC 2022,并纳入国际电工委员会(IEC)的标准体系。

下面这些东西,韩国和日本(曾经)用的比较多:

  • ISO-2022-CN,
  • ISO-2022-CN-EXT,
  • ISO-2022-JP,
  • ISO-2022-JP-1,
  • ISO-2022-JP-2
  • ISO-2022-KR

基本被unicode取代了

EUC(Extended Unix Code)

EUC(Extended Unix Code,扩展 UNIX 编码) 是一种多字节字符编码,用于在 UNIX 和类 UNIX 系统中表示多种东亚语言字符集(如日文、韩文和中文)。EUC 是基于 ISO 2022 编码标准的扩展,能够在同一编码中支持多种字符集,并且保持对 ASCII 的兼容性。

这个编码日本和韩国还在用,在前面python的表格中,可以看到下面4个:

  • euc_jp
  • euc_jis_2004
  • euc_jisx0213
  • euc_kr

在中国,euc_cn 需要配合 GB2312 使用,但是 GB2312 已经被 GBK 和 GB18030 取代。

Unicode

小结一下:

  • ASCII:用于英语和西方语言的 7 位编码。
  • ISO 8859 系列:分为多个版本,用于不同的西方语言。
  • GB2312:用于简体中文的字符集。
  • Big5:用于繁体中文的字符集。
  • ISO/IEC 2022:没能很好解决这个问题

可以发现存在致命问题:

  • 不兼容性:不同编码系统之间无法互相解读。
  • 字符冲突:同一个字节值在不同编码中可能代表完全不同的字符。
  • 缺乏全球化支持:无法同时支持多种语言文字。

如何解决?

Unicode 与 UCS

为了统一全球字符编码,早期出现了两个独立的组织:

  • Unicode 联盟(Unicode Consortium) 于 1987 年成立。1991 年发布Unicode 1.0,支持固定长度的 16 位编码,能够容纳 65,536 个字符。
  • UCS(通用字符集,Universal Character Set)由 ISO/IEC 10646 国际标准定义的。第一个版本(ISO 10646-1:1993)发布于 1993 年,定义了一个更大的编码空间(31 位),远远超过 Unicode 的初始设计范围。

从 Unicode 2.0 起(1996 年),Unicode 和 ISO/IEC 10646 的编码点完全同步。Unicode 2.0 版本扩展到 21 位范围(0x000000–0x10FFFF),并引入了补充平面,覆盖了更多的字符。

UCS-2、UCS-4、UTF-8、UTF-16、UTF-32

  • UCS-2:早期 Unicode 编码方式,定长2字节,现已淘汰。【容易和UTF-16混淆】
  • UTF-8:最流行的 Unicode 编码方式1~4个字节,与 ASCII兼容,适用于网络和跨平台文本处理。
  • UTF-16:广泛用于操作系统和编程语言的内部表示,变长的编码方式,2个字节或4个字节。【既不和ASCII兼容,也不定长,集 UTF-8 和 UTF-32 缺点于一身??】
  • UTF-32:定长,尽管和ASCII不兼容,但它编码简单

放个表:

年份 事件
1991 UCS-2 发布:Unicode 1.0 中的编码方式,使用固定 2 字节表示字符,仅支持 BMP 范围(0x0000–0xFFFF)。
1992 UTF-8 设计完成:由 Ken Thompson 和 Rob Pike 设计,作为一种变长编码方式,兼容 ASCII。
1993 UTF-8 标准化:成为 Unicode 的正式编码方式(RFC 2279)。
1996 UTF-16 发布:Unicode 2.0 推出,扩展编码范围至 0x0000–0x10FFFF,引入补充平面字符,支持代理对。
1996 UCS-4 发布:ISO/IEC 10646 定义的 4 字节固定长度编码,支持完整 Unicode 范围。
1996 UTF-7 标准化(RFC 1642):一种为电子邮件和其他 7 位传输协议设计的 Unicode 编码方式,但逐渐被废弃。
1999 UTF-8 更新(RFC 3629):限制编码范围为 0x0000–0x10FFFF,与 Unicode 的定义保持一致。
2000s UTF-8 成为主流:随着互联网的发展,UTF-8 被广泛应用于网页、协议(如 HTML、JSON)和操作系统中。
2000s UTF-16 流行:Windows、Java、C# 等系统和语言内部采用 UTF-16 作为默认编码方式。
现代 UCS-2 被淘汰:由于无法支持补充平面字符,UCS-2 被 UTF-16 完全取代。
现代 UTF-32 用于内部处理:虽然内存占用高,但其编码简单,适用于数据库和编译器等场景。

附表

标准

  • ISO/IEC 646
  • ISO/IEC 8859
  • ISO/IEC 2022
  • ISO/IEC 10646

IANA 字符集注册表

IANA 字符集注册表(IANA Character Sets Registry) 是由 IANA(Internet Assigned Numbers Authority) 维护的一个标准化列表,用于记录和规范互联网上使用的 字符集(Character Sets)。该注册表为各种网络协议(如 HTTP、SMTP、MIME 等)提供了标准化的字符集名称、编号和相关信息,以确保跨平台、跨语言环境下的互操作性。

每个字符集分配一个唯一的 MIBenum 值,用于在 MIB(Management Information Base,管理信息库) 中标识字符集。范围划分:

  • 0-2:保留。
  • 3-999:由标准化组织分配的字符集。
  • 1000-1999:Unicode 和 ISO/IEC 10646 编码。
  • 2000 及以上:厂商特定字符集。

ANSI 编码

虽然名称中含有“ANSI”(American National Standards Institute,美国国家标准协会),但实际上它与 ANSI 标准没有直接关系,而是 Microsoft 自定义的字符集。

在 Windows 系统中,ANSI 编码实际上是基于 代码页(Code Page) 的单字节或多字节字符编码方案。每种语言或语言组在 Windows 中对应一个特定的代码页,ANSI 编码依赖这些代码页来表示特定语言的字符集。

一些常见的代码页:

代码页(Code Page) 描述 语言/区域 对应的字符集
1250 中欧字符集 波兰语、捷克语、匈牙利语等 Windows-1250
1251 西里尔字符集 俄语、乌克兰语、保加利亚语等 Windows-1251
1252 西欧字符集(ANSI 默认) 英语、法语、德语、西班牙语等 Windows-1252
1253 希腊字符集 希腊语 Windows-1253
1254 土耳其字符集 土耳其语 Windows-1254
1255 希伯来字符集 希伯来语 Windows-1255
1256 阿拉伯字符集 阿拉伯语 Windows-1256
1257 波罗的海字符集 拉脱维亚语、立陶宛语等 Windows-1257
1258 越南语字符集 越南语 Windows-1258
936 简体中文字符集 简体中文 GB2312(CP936)
950 繁体中文字符集 繁体中文 Big5(CP950)
932 日文字符集 日语 Shift_JIS(CP932)
949 韩文字符集 韩语 KS C 5601(CP949)

Python内置编码的列表

作为参考,此处把Python手册中的编码表格列出来(注意,表格别名只列出部分名字)

编码名称 别名 语言
ascii 646, us-ascii 英语
big5 big5-tw, csbig5 繁体中文
big5hkscs big5-hkscs, hkscs 繁体中文
cp037 IBM037, IBM039 英语
cp273 273, IBM273, csIBM273 德语
cp424 EBCDIC-CP-HE, IBM424 希伯来语
cp437 437, IBM437 英语
cp500 EBCDIC-CP-BE, EBCDIC-CP-CH, IBM500 西欧
cp720 - 阿拉伯语
cp737 - 希腊语
cp775 IBM775 波罗的海语言
cp850 850, IBM850 西欧
cp852 852, IBM852 中欧和东欧
cp855 855, IBM855 保加利亚语、白俄罗斯语、马其顿语、俄语、塞尔维亚语
cp856 - 希伯来语
cp857 857, IBM857 土耳其语
cp858 858, IBM858 西欧
cp860 860, IBM860 葡萄牙语
cp861 861, CP-IS, IBM861 冰岛语
cp862 862, IBM862 希伯来语
cp863 863, IBM863 加拿大法语
cp864 IBM864 阿拉伯语
cp865 865, IBM865 丹麦语、挪威语
cp866 866, IBM866 俄语
cp869 869, CP-GR, IBM869 希腊语
cp874 - 泰语
cp875 - 希腊语
cp932 932, ms932, mskanji, ms-kanji, windows-31j 日语
cp949 949, ms949, uhc 韩语
cp950 950, ms950 繁体中文
cp1006 - 乌尔都语
cp1026 ibm1026 土耳其语
cp1125 1125, ibm1125, cp866u, ruscii 乌克兰语
cp1140 ibm1140 西欧
cp1250 windows-1250 中欧和东欧
cp1251 windows-1251 保加利亚语、白俄罗斯语、马其顿语、俄语、塞尔维亚语
cp1252 windows-1252 西欧
cp1253 windows-1253 希腊语
cp1254 windows-1254 土耳其语
cp1255 windows-1255 希伯来语
cp1256 windows-1256 阿拉伯语
cp1257 windows-1257 波罗的海语言
cp1258 windows-1258 越南语
euc_jp eucjp, ujis, u-jis 日语
euc_jis_2004 jisx0213, eucjis2004 日语
euc_jisx0213 eucjisx0213 日语
euc_kr euckr, korean, ksc5601, ks_c-5601, ks_c-5601-1987, ksx1001, ks_x-1001 韩语
gb2312 chinese, csiso58gb231280, euc-cn, euccn, eucgb2312-cn, gb2312-1980, gb2312-80, iso-ir-58 简体中文
gbk 936, cp936, ms936 统一中文(Unified Chinese)
gb18030 gb18030-2000 统一中文(Unified Chinese)
hz hzgb, hz-gb, hz-gb-2312 简体中文
iso2022_jp csiso2022jp, iso2022jp, iso-2022-jp 日语
iso2022_jp_1 iso2022jp-1, iso-2022-jp-1 日语
iso2022_jp_2 iso2022jp-2, iso-2022-jp-2 日语、韩语、简体中文、西欧、希腊语
iso2022_jp_2004 iso2022jp-2004, iso-2022-jp-2004 日语
iso2022_jp_3 iso2022jp-3, iso-2022-jp-3 日语
iso2022_jp_ext iso2022jp-ext, iso-2022-jp-ext 日语
iso2022_kr csiso2022kr, iso2022kr, iso-2022-kr 韩语
latin_1 iso-8859-1, iso8859-1, 8859, cp819, latin, latin1, L1 西欧
iso8859_2 iso-8859-2, latin2, L2 中欧和东欧
iso8859_3 iso-8859-3, latin3, L3 世界语、马耳他语
iso8859_4 iso-8859-4, latin4, L4 波罗的海语言
iso8859_5 iso-8859-5, cyrillic 保加利亚语、白俄罗斯语、马其顿语、俄语、塞尔维亚语
iso8859_6 iso-8859-6, arabic 阿拉伯语
iso8859_7 iso-8859-7, greek, greek8 希腊语
iso8859_8 iso-8859-8, hebrew 希伯来语
iso8859_9 iso-8859-9, latin5, L5 土耳其语
iso8859_10 iso-8859-10, latin6, L6 北欧语言
iso8859_11 iso-8859-11, thai 泰语
iso8859_13 iso-8859-13, latin7, L7 波罗的海语言
iso8859_14 iso-8859-14, latin8, L8 凯尔特语言
iso8859_15 iso-8859-15, latin9, L9 西欧
iso8859_16 iso-8859-16, latin10, L10 东南欧语言
johab cp1361, ms1361 韩语
koi8_r - 俄语
koi8_t - 塔吉克语
koi8_u - 乌克兰语
kz1048 kz_1048, strk1048_2002, rk1048 哈萨克语
mac_cyrillic maccyrillic 保加利亚语、白俄罗斯语、马其顿语、俄语、塞尔维亚语
mac_greek macgreek 希腊语
mac_iceland maciceland 冰岛语
mac_latin2 maclatin2, maccentraleurope, mac_centeuro 中欧和东欧
mac_roman macroman, macintosh 西欧
mac_turkish macturkish 土耳其语
ptcp154 csptcp154, pt154, cp154, cyrillic-asian 哈萨克语
shift_jis csshiftjis, shiftjis, sjis, s_jis 日语
shift_jis_2004 shiftjis2004, sjis_2004, sjis2004 日语
shift_jisx0213 shiftjisx0213, sjisx0213, s_jisx0213 日语
utf_32 U32, utf32 所有语言
utf_32_be UTF-32BE 所有语言
utf_32_le UTF-32LE 所有语言
utf_16 U16, utf16 所有语言
utf_16_be UTF-16BE 所有语言
utf_16_le UTF-16LE 所有语言
utf_7 U7, unicode-1-1-utf-7 所有语言
utf_8 U8, UTF, utf8, cp65001 所有语言
utf_8_sig - 所有语言

Qt支持的编码

在Qt6,QStringConverter 支持如下编码:

  • UTF-8
  • UTF-16
  • UTF-16BE
  • UTF-16LE
  • UTF-32
  • UTF-32BE
  • UTF-32LE
  • ISO-8859-1 (Latin-1)
  • The system encoding

Qt 的 QTextCodec 支持如下的编码(注:Qt6中QTextCodec已经被边缘化了):

  • Big5
  • Big5-HKSCS
  • CP949
  • EUC-JP
  • EUC-KR
  • GB18030
  • HP-ROMAN8
  • IBM 850
  • IBM 866
  • IBM 874
  • ISO 2022-JP
  • ISO 8859-1 to 10
  • ISO 8859-13 to 16
  • Iscii-Bng, Dev, Gjr, Knd, Mlm, Ori, Pnj, Tlg, and Tml
  • KOI8-R
  • KOI8-U
  • Macintosh
  • Shift-JIS
  • TIS-620
  • TSCII
  • UTF-8
  • UTF-16
  • UTF-16BE
  • UTF-16LE
  • UTF-32
  • UTF-32BE
  • UTF-32LE
  • Windows-1250 to 1258

参考

  • https://docs.python.org/3/library/codecs.html#standard-encodings
  • https://en.wikipedia.org/wiki/EBCDIC
  • https://en.wikipedia.org/wiki/ASCII
  • https://en.wikipedia.org/wiki/Extended_ASCII
  • https://en.wikipedia.org/wiki/GBK_(character_encoding)
  • https://en.wikipedia.org/wiki/GB_2312
  • https://en.wikipedia.org/wiki/Big5
  • https://en.wikipedia.org/wiki/Unicode
  • https://en.wikipedia.org/wiki/ISO/IEC_646
  • https://en.wikipedia.org/wiki/ISO/IEC_10646
  • https://en.wikipedia.org/wiki/ISO/IEC_2022
  • https://en.wikipedia.org/wiki/Extended_Unix_Code
  • https://www.iana.org/assignments/character-sets/character-sets.xml

Python C++