与UNIX / Linux环境交互时,为什么使用UTF-8编码?
我知道这是习惯,但是为什么呢?是否存在真正的技术原因,为什么任何其他方法都不是一个好主意,还是仅基于编码和向后兼容的历史?另外,不使用UTF-8
而是使用其他一些编码(最值得注意的是UTF-16
)会有什么危险?
编辑:通过交互,我主要是指shell
和libc
。
解决方案
我相信这主要是UTF8与ASCII所提供的向后兼容性。
要回答"危险"问题,我们需要指定"交互"的含义。我们是要与Shell,libc还是与内核进行交互?
是的,这是出于兼容性原因。 UTF-8可向后兼容ASCII。 Linux / Unix是基于ASCII的,因此它很有意义。
部分原因是文件系统期望NUL('\ 0')字节终止文件名,因此UTF-16不能很好地工作。我们必须修改很多代码才能进行更改。
我认为7位ASCII没问题。
严肃地讲,Unicode在事物方案中相对较新,而UTF-8与ASCII向后兼容,并且对于典型文件使用较少的空间(一半),因为它每个代码点(字符)使用1-4个字节,而UTF-16使用每个代码点2个或者4个字节(字符)。
UTF-16对于内部程序使用是更可取的,因为它的宽度更简单。它的前身UCS-2每个代码点正好是2个字节。
现代Unix使用UTF-8,但这并不总是正确的。在仅使用了几年的RHEL2上,默认值为
$ locale LANG=C LC_CTYPE="C" LC_NUMERIC="C" LC_TIME="C" LC_COLLATE="C" LC_MONETARY="C" LC_MESSAGES="C" LC_PAPER="C" LC_NAME="C" LC_ADDRESS="C" LC_TELEPHONE="C" LC_MEASUREMENT="C" LC_IDENTIFICATION="C" LC_ALL=
C / POSIX语言环境应为7位ASCII兼容编码。
但是,正如乔纳森·莱夫勒(Jonathan Leffler)所述,在字符序列中允许使用NUL字节的任何编码在Unix上都是行不通的,因为系统API的语言环境是未知的。字符串均假定为以\ 0结尾的字节序列。
我认为这是因为期望ASCII输入的程序无法处理UTF-16等编码。对于大多数字符(在0-255范围内),这些程序会将高字节视为NUL / 0字符,该字符在许多语言和系统中用于标记字符串的结尾。 UTF-8不会发生这种情况,因为UTF-8的目的是避免嵌入NUL并与字节顺序无关。
正如jonathan-leffler提到的那样,主要问题是ASCII空字符。传统上,C期望字符串以null终止。因此,标准C字符串函数将阻塞包含等于ASCII空(0x00)字节的任何UTF-16字符。虽然可以肯定地支持广泛的字符编程,但UTF-16不适用于文件名,文本文件,环境变量中的Unicode外部编码。
此外,UTF-16和UTF-32都具有大字节序和小字节序方向。要解决此问题,我们将需要外部元数据(例如MIME类型或者字节方向标记)。它指出,
Where UTF-8 is used transparently in 8-bit environments, the use of a BOM will interfere with any protocol or file format that expects specific ASCII characters at the beginning, such as the use of "#!" of at the beginning of Unix shell scripts.
UTF-16的前身(称为UCS-2,不支持代理对)也存在相同的问题。应避免使用UCS-2.
我相信,当Microsoft开始使用两字节编码时,尚未分配大于0xffff的字符,因此使用两字节编码意味着没有人会担心字符长度不同。
现在有超出此范围的字符,因此无论如何我们都必须处理不同长度的字符,为什么有人会使用UTF-16?如果他们今天取消对unicode的支持,我怀疑Microsoft是否会做出不同的决定。