应用程序如何知道字符编码?
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?
或者:
- (他们猜测——也许是启发式的。这不是 "knowing"。)
- 他们会准确地告诉您使用哪一个(通过文档、标准、惯例等)。 (这也不是真的 "knowing"。)
- 他们允许您告诉他们您使用的是哪一个。
这是你的文件;你必须知道。
假设我有两个文件如下:
$ 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?
或者:
- (他们猜测——也许是启发式的。这不是 "knowing"。)
- 他们会准确地告诉您使用哪一个(通过文档、标准、惯例等)。 (这也不是真的 "knowing"。)
- 他们允许您告诉他们您使用的是哪一个。
这是你的文件;你必须知道。