“编码”,“字符集”和“代码页”有何区别?

45

我真的在努力提高自己的技能。我对国际化概念这样的东西有一定的实用经验,但是我需要更好地了解背后的理论知识。

我已经阅读了Spolsky的文章,但我仍然不清楚,因为这三个术语经常会被混淆使用,即使在那篇文章中也是如此。我认为其中至少两个是在谈论同一件事情。

我怀疑很多开发者每天都在应对这些问题而匆忙通过,但我不想再成为那些开发者之一。

5个回答

53
一个“字符集”就是一个明确定义的不同字符列表。
“编码”是一个字符集(今天通常是Unicode)和(通常是基于字节的)技术表示之间的映射。
UTF-8是一种编码,但不是一个字符集。它是Unicode字符集的编码(*)
这种混淆是因为大多数其他知名的编码(例如:ISO-8859-1)最初作为单独的字符集出现。然后,当Unicode作为大多数这些字符集的超集出现时,将它们视为同一(Unicode)字符集的不同(但部分)编码变得可能,而不仅仅是孤立的字符集。以这种方式查看它们允许您通过Unicode轻松地在它们之间进行转换,如果它们只是孤立的字符集,这是不可能的。但仍然有意义称它们为字符集,因此可以使用任何一种术语。
“代码页”是源自IBM的术语,其中选择要显示的符号集。该术语继续被DOS和Windows使用,直到Unicode-aware Windows,在那里它仅充当具有编号标识符的编码。虽然编号的“代码页”并非本质上仅限于Microsoft,但今天这个术语几乎总是指Windows已知的编码。
当谈论code page ‹some number› 时,通常是指Windows特定的编码,而不是由标准机构设计的编码。例如,code page 28591通常不会用这个名称来引用它,而只是简单地称为“ISO-8859-1”。基于ISO-8859-1(用一些额外字符替换其中一些控制码)的Windows-specific Western European编码通常被称为“code page 1252”。
[*:所有UTF都是编码,而不是字符集,但这种情况并非仅限于Unicode。例如,日本标准JIS X 0208定义了一个字符集和两种不同的字节编码:有点令人不舒服的高字节编码(“Shift-JIS”)和深度可怕的转义切换编码(“JIS”)。]

使用ISO/IEC 8859-1,据说这是ISO标准(由于ISO的付费墙无法确定)。该标准不包括控制字符,但代码页包括(00-1F7F-9F)。谁定义了代码页编码并做出了决定?然后,windows-1252代码页将某些控制字符编码替换为不同的可打印字符编码。希望您能在该示例的背景下进行更详细的解释。谢谢! - mattpr
如果代码页只是一种编码方式,那么它编码的是哪种字符集? - undefined

10

字符集就是包含可使用的字符的集合。
每个字符都映射到一个称为代码点的整数。
这些代码点在内存中的表示方式就是编码。编码只是将代码点(U+0041 - 字符'A'的Unicode代码点)转换为原始数据(位和字节)的方法。


8
一个字符集是一组字符,即表示通信单位的视觉符号“字形”。字母a是一个字形,€(欧元符号)也是一个字形。字符集通常将整数(码点)映射到每个字符,但编码决定了字符的二进制/字节级表示方式。我是一个Ruby程序员,以下是一些示例,以帮助你理解这些概念。这揭示了Unicode字符集如何将码点映射到字符,但不涉及每个字节的存储方式。(Ruby 1.9默认使用Unicode字符串。)
>> 'a'.codepoints.to_a
=> [97]
>> '€'.codepoints.to_a
=> [8364]

由于8364(十进制)太大,无法放入一个字节中,因此存在各种编码策略来指定从Unicode 代码点到一个或多个字节的翻译。UTF-8编码可能是这些编码中最受欢迎的一种。(如果您想深入了解实现,请参考维基百科上的UTF-8编码算法。)请注意,UTF-8编码只在Unicode字符集的上下文中才有意义。
以下内容揭示了UTF-8编码如何将每个Unicode字符存储为字节(0到255的十进制数)。 (Ruby 1.9的默认编码是UTF-8。)
>> 'a'.bytes.to_a
=> [97]
>> '€'.bytes.to_a
=> [226, 130, 172]

以下是使用 ISO-8859-15 字符集 的相同内容:

>> 'a'.encode('iso-8859-15').codepoints.to_a
=> [97]
>> '€'.encode('iso-8859-15').codepoints.to_a
=> [164]

以及ISO-8859-15 编码:

>> 'a'.encode('iso-8859-15').bytes.to_a
=> [97]
>> '€'.encode('iso-8859-15').bytes.to_a
=> [164]

请注意,ISO-8859-15代码点与字节表示匹配。
这篇博客文章可能会有所帮助:http://graysoftinc.com/character-encodings/what-is-a-character-encoding。如果您不想过于专注于Ruby,则前三个条目很好。

8
我认为Joel的文章基本上是正确的——正是字符集和存储演变的历史使得这种情况发生。
对于我过于简化的观点,以下是:
- 字符集(ASCII、EBCDIC、UNICODE)是字符的数字表示,独立于存储考虑。 - 编码与字符的高效存储有关,如ANSI、UTF-7、UTF-8等,用于文件、跨网络传输等。 - 代码页是“权宜之计”,当需要添加新字符(但不想增加存储容量)时,某些字符只能在代码页的附加上下文中知道。
在我看来,维基百科目前并没有帮助澄清问题,因为它将代码页定义为“字符编码的另一个名称”,并将“字符集”重定向到“字符编码”

2
在我看来,没有所谓的“ANSI”编码。这个名称是一个误称。 - nn0p
1
@nn0p 没错,虽然“ANSI”的使用在微软的文档、API甚至各种产品中都非常普遍,有时很难知道应该在哪里划线。不过,我刚刚写了一篇关于SQL Server文档和元数据混淆ANSI、ISO-8859-1和Windows-1252作为同一事物的文章:SQL Server Collations: What does “CP1” mean in “SQL_Latin1_General_CP1_CI_AS”? - Solomon Rutzky

2
这本书中关于 Unicode 的章节《高级 Perl 编程》 包含了我所见过的最好的编码、字符集和 Unicode 其他实体的描述。不幸的是,我认为它在网上不免费提供。

1
我有Safari订阅。刚刚下载了这一章,谢谢。 - Deane

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接