我知道这是习惯,但为什么?是否存在真正的技术原因,为什么任何其他方式都是一个非常糟糕的想法,还是仅仅基于编码和向后兼容的历史?此外,不使用UTF-8
的危险是什么,还有一些其他编码(最值得注意的是,UTF-16
)?
编辑:通过互动,我主要是指shell
和libc
。
答案 0 :(得分:15)
部分原因是文件系统期望NUL('\ 0')字节终止文件名,因此UTF-16不能很好地工作。您必须修改大量代码才能进行更改。
答案 1 :(得分:8)
正如jonathan-leffler所提到的,主要问题是ASCII空字符。传统上,C期望字符串为空终止。因此,标准C字符串函数将阻塞任何包含等于ASCII null(0x00)的字节的UTF-16字符。虽然您可以使用广泛的字符支持进行编程,但UTF-16不是filenames, text files, environment variables中适合的Unicode外部编码。
此外,UTF-16和UTF-32都具有大端和小端方向。要解决此问题,您需要外部元数据,如MIME类型或Byte Orientation Mark。它指出,
透明地使用UTF-8的地方 在8位环境中,使用BOM 会干扰任何协议或 期望特定的文件格式 开头的ASCII字符, 比如使用“#!”在... Unix shell脚本的开头。
UTF-16的前身,称为UCS-2,不支持代理对,具有same issues。应避免使用UCS-2。
答案 2 :(得分:2)
我认为这主要是UTF8用ASCII提供的向后兼容性。
对于“危险”问题的答案,您需要通过“互动”来指定您的意思。你的意思是与shell,libc或内核进行交互吗?
答案 3 :(得分: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。
终止的字节序列答案 4 :(得分:1)
我相信当微软开始使用双字节编码时,尚未分配0xffff以上的字符,因此使用双字节编码意味着没有人不必担心字符长度不同。
现在有这个范围之外的字符,所以你不得不处理不同长度的字符,为什么有人会使用UTF-16?我怀疑如果他们今天设计了他们的unicode支持,微软会做出不同的决定。
答案 5 :(得分:0)
是的,这是出于兼容性原因。 UTF-8向后兼容ASCII。 Linux / Unix是基于ASCII的,所以它只是有意义的。
答案 6 :(得分:0)
我认为7位ASCII很好。
说真的,Unicode在事物的方案中相对较新,而UTF-8向后兼容ASCII,并且对于典型文件使用较少的空间(一半),因为它每个代码点(字符)使用1到4个字节,而UTF-16每个代码点(字符)使用2或4个字节。
由于宽度更简单,UTF-16更适合内部程序使用。它的前身UCS-2对于每个代码点都是2个字节。
答案 7 :(得分:0)
我认为这是因为期望ASCII输入的程序将无法处理UTF-16等编码。对于大多数字符(在0-255范围内),这些程序将高字节视为NUL / 0字符,它在许多语言和系统中用于标记字符串的结尾。在UTF-8中不会发生这种情况,UTF-8旨在避免嵌入式NUL并且与字节顺序无关。