作者:斯拉夫·米哈伊洛夫;    翻译:Betty


我的上一篇文章是《不同的数据类型和关于它们的一些技巧》。我们也谈了一点关于字符的内容。然而,由于存在一个被称作编码的花哨的计算机编程术语,这些字符使用起来可能有点奇怪。

今天,朋友请我去搞定他的电影字幕。他曾告诉我,一些奇怪的符号总是出现。于是他试着重新安装Windows和不断变化各种选项,但似乎没有任何效果。他显然不知道编码是什么。不过,我想这是正常的,因为他没有CS(计算机科学与技术)背景。但似乎有很多开发者(包括过去的我)都不知道编码是什么意思。当然,他们可能听说过UTF-8,但编码是什么?我们有ASCII,对吧?

好吧,我将在这篇文章中讨论编码问题,因为我认为这对任何从事编程和计算机信息处理的人来说都是至关重要的。似乎没有多少编程基础课程详细地介绍了这个话题。

字符集

上一次,我讲到了关于字符是如何利用一个名为ASCII的表来将数字映射到不同的字母和符号的问题。实际上,这个表允许我们使用128个值来存储英语字母表中所有必要的字母和符号、以及一组备用的128个其他的值来满足不同的需要。这似乎圆满解决了过去的问题。但我们有时候需要内化。也就是说,要显示来自世界各地的不同字母表中的字母。例如:波斯语或阿拉伯语。为此,人们开始使用剩余的128个值来表示来自他们自己的文化中的字母和符号。但是这种方法在很长一段时间内似乎都不太有效。

Unicode

不久,万国码字符集诞生。它用来解决对于不同语言和文化的表示,其基本思想是为所有不同的字符提供一个唯一的代码点。这就意味着这个字符集可以代表高于8位号的值。在十六进制中用于表示万国码字符的符号是U + XXXX(这是16进制数字系统)。例如,如果你想用万国码来显示西里尔字符я,就要使用代码U+044F。这个字符集为来自不同文化的所有不同的符号提供代码点,它甚至为那些尚未定义的符号留出了备用码点。你可以通过查看unicode-table.com来获取一个完整的万国码字符列表。

Encoding

现在我们知道如何处理来自不同文化的字符了,是不是万事大吉了呢?我们还有一个问题要解决:我们如何将这些字符存储在内存中呢?乍一看,这个问题似乎有点多余。因为我们知道字符的代码点是什么,我们只需要存储这些代码点的值就可以了。这是一个合理的论点,也是将字符存储在内存中的一种方式。所以如果我们要把西里尔字符я存储在内存中,我们只需把值“04 4F”用2个字节连续存储在内存中。这样做的效果将会相当好。

这种方法存在的问题

不过,想象一下:我们只想储存一个普通的英文文本,而不需要任何花哨的国际符号。我们怎么办?

像从前一样,我们可以用2个字节来存储字母。例如,英文字母A在万国码中对应的值是101(ASCII是万国码的子集),可以存储为00 41。但你现在可能注意到了:该字母的存储多占用了一个字节,因为A可以很容易地只用一个字节来存储。这就意味着,以前用ASCII编码的文本现在改为用Unicode(万国码)编码后,所占用的字节是原来的两倍。在这种情况下,不使用Unicode实际上也是合理的。这种存储字符(或者实际上被称为字符编码)的方式被称为UCS-2。

但后来人们想到了这一点,并说:“好吧,难道我们不能用1个字节存储小字符,用2个字节存储大字符吗?”于是,他们提供了另一种编码:UTF-8。UTF-8实际上是现在最为广泛使用的编码。

但除此之外,还有另外一个问题。例如,我们是以什么顺序将字节存储在内存中的?我们应该把A存储为00 41还是41 00?这就需要在文本中增加一些额外的标题信息来指定它的编码方式。

这些问题和各种其他问题造成了目前各种编码的产生。但正如我所提到的,其中应用最广泛的是UTF-8。所以当我的朋友把他的字幕用UTF-8进行编码、但又试图用一种不同的不兼容的编码来展示字幕的时候,各种奇怪的字符就出现在屏幕上了。

如何处理代码中的字符集和编码问题?

看来大多数现代语言都为我们解决了这个问题。例如,C# 和 Java把字符存储为2个字节,以便可以对不同的语言进行编码。

然而,C++和C在处理Unicode(万国码)字符串时有一个问题。主要问题在于这些语言中的字符数据类型占用1个字节。这就意味着你应该使用C语言中的外部库或结构来处理Unicode文本。在C++中,你可以使用wchar_t数据类型来代替char。但是你也应该停止使用标准函数,而是使用更多的Unicode驱动的函数。最后但并非最不重要的一点是,你不应该使用str++来迭代一个字符串,因为Unicode字符可以占用数量不定的字节。

结论

我只是触及了字符集和编码工作的表面。但我的目标不是提供一个如何使用它们的详细文档。相反,我想为你提供足够的知识来理解基本概念,并帮助你在代码实践中做好这方面的准备。

至少,你可能会遇到一个电影字幕的编码问题。如果是这样的话,你现在知道如何解决这个问题了。

如果想要阅读关于字符集和编码的更全面的一个文本,你可以看看关于这一主题的著名文章:The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!) 每个软件开发者绝对、一定要了解的关于万国码和字符集的绝对最低限度的知识(不要找借口!)

下次见。我们将回到对待二进制数的问题上,并介绍如何使用二进制操作来巧妙处理它们。