应用程序如何知道字符编码?

How do applications know character encoding?

假设我有两个文件如下:

$ ll
total 8
-rw-rw-r--. 1 matias matias 6 Nov 27 20:25 ascii.txt
-rw-rw-r--. 1 matias matias 8 Nov 28 21:57 unicode.txt

两者都包含一行文本,但第二个文件中有一个额外的字符,如下所示(希腊字母 Sigma):

$ cat ascii.txt
   matias
$ cat unicode.txt
   matiasΣ

如果我通过 file 命令传递它们,这是输出:

$ file *
  ascii.txt:   ASCII text, with no line terminators
  unicode.txt: UTF-8 Unicode text, with no line terminators

这看起来不错。现在,如果我对文件进行 hexdump,我会得到:

 $ hexdump -C ascii.txt
   00000000  6d 61 74 69 61 73                     |matias|
   00000006

 $ hexdump -C unicode.txt
   00000000  6d 61 74 69 61 73 ce a3               |matias..|
   00000008

所以,我的问题是,作为 cat 的应用程序如何知道最后两个字节实际上是一个 单个 Unicode 字符。如果我单独打印最后两个字节,我会得到:

 $ printf '%d' '0xce'
   206
 $ printf '%d' '0xa3'
   163

扩展 ASCII 中的哪些是:

 $ py3 -c 'print(chr(206))'
   Î
 $ py3 -c 'print(chr(163))'
   £

我的逻辑有问题吗?我在这里错过了什么?

命令行工具使用字节——它们接收字节并发送字节。 字符的概念——由单个或多个字节表示——是对原始字节的任务特定解释。 当您在 UTF-8 文件上调用 cat 时,我假设它只是转发它读取的字节而不关心字符。

但是您的终端必须显示 cat 的输出, 会注意将字节解释为字符并为字节序列显示单个字符206、163。 从它的配置(locale env vars 等)来看,您的终端显然假设文本 IO 使用 UTF-8 发生。 如果违反此假设(例如,如果命令单独发送字节 206,这是无效的 UTF-8),您将看到符号或其他文本垃圾。 由于 UTF-8 被设计为向后兼容 ASCII,ASCII 文本文件可以像 UTF-8 文件一样对待( UTF-8)。

虽然 cat 可能不关心字符,但许多其他命令会关心,例如。 wc -m 命令计算文本文件中的字符数(不是字节数!)。 这些命令都需要知道 UTF-8(或任何您的终端编码)如何将字节映射到字符,反之亦然。 例如,当您在 Python 中 print(chr(206)) 时,它会将字节 195、142 发送到 STDOUT,因为: (a) 它已经计算出您的终端需要 UTF-8 和 (b) 字符“ε”(Unicode 代码点 206 对应)用 UTF-8 中的这两个字节表示。 最后,终端显示“È”,因为它把两个字节解码成对应的字符。

How do applications know character encoding?

或者:

  1. (他们猜测——也许是启发式的。这不是 "knowing"。)
  2. 他们会准确地告诉您使用哪一个(通过文档、标准、惯例等)。 (这也不是真的 "knowing"。)
  3. 他们允许您告诉他们您使用的是哪一个。

这是你的文件;你必须知道。