UTF-8可以包含零字节吗?

76

UTF-8字符串能包含零字节吗?我将通过ASCII纯文本协议发送它,我应该使用类似base64的编码进行编码吗?


7
UTF-8 使用 8 位,因此无法通过 ASCII(7 位)纯文本发送它。采用 Base64 编码可以解决这个问题,但并不是由于空字节的存在。 - Tim Pietzcker
3个回答

117

是的,在UTF8中,零字节表示的是代码点0,也就是NUL。没有其他的Unicode代码点会在其UTF8编码中出现一个零字节。

可能的代码点及其UTF8编码如下:

Range              Encoding  Binary value
-----------------  --------  --------------------------
U+000000-U+00007f  0xxxxxxx  0xxxxxxx

U+000080-U+0007ff  110yyyxx  00000yyy xxxxxxxx
                   10xxxxxx

U+000800-U+00ffff  1110yyyy  yyyyyyyy xxxxxxxx
                   10yyyyxx
                   10xxxxxx

U+010000-U+10ffff  11110zzz  000zzzzz yyyyyyyy xxxxxxxx
                   10zzyyyy
                   10yyyyxx
                   10xxxxxx

你可以看到,所有非零ASCII字符都表示为它们自己,而所有的多字节序列在所有字节中都有高位是1。

你需要小心你的ASCII纯文本协议不会把非ASCII字符视为坏的(因为这将包括所有非ASCII码点)。


9
Pacerier,"无效的UTF8"不存在。根据定义,如果它不合法,那么它就不是UTF8 :-) - paxdiablo
6
UTF-8的定义因为过多的使用而被过度负载,现在常指“按UTF-8解释的字节”,而非最初的“符合UTF-8的字节”。 - Pacerier
3
Pacerier,你提出了一个很好的观点,可能是这种情况,但那些人只是“错了”。就像声称EBCDIC是ASCII、COBOL是C或法语是斯瓦希里的人一样错了。我看不出任何合理的解释,会称某些东西是UTF8,如果它实际上不符合UTF8规则的话,它就不是有效的UTF8,那么它只是某种任意的字节流。 - paxdiablo
4
@gardarh说,0x0800的UTF-8编码不是08, 00,而是e0, a0, 80,完全没有零字节。可以参考http://www.fileformat.info/info/unicode/char/0800/index.htm了解更多细节,但基本上它是答案中第三个范围内的第一个值,*所有*字节都具有高位设置,因此不存在`00`的可能性。 - paxdiablo
1
值得指出的是,有一种修改过的UTF-8,它将U+0000编码为两个字节的序列\xC0\x80。使用修改过的UTF-8,空字节永远不会出现在编码文本中,因此可以安全地使用空字节来表示编码文本流的结束。(然而,我怀疑UTF-8 - 修改过或未修改过 - 是否能够在OP想要的ASCII纯文本协议上生存下来。第8位有点重要!) - Ted Hopp
显示剩余8条评论

4
ASCII文本只能使用0到127之间的字节值。UTF-8文本没有这种限制,UTF-8编码的文本可能会设置其高位。因此,在不保证传输该高位安全的通道上发送UTF-8文本是不安全的。
如果你被迫处理ASCII-only通道,Base-64是一个合理(虽然不特别空间有效)的选择。但您确定您受到7位数据的限制吗?在今天,这有些不寻常。

你可以使用 base-128 处理 UTF-8/ASCII-only 通道中的二进制数据,因为较低的 128 字节值都是单字节码点,据我所知。 - Janus Troelsen

3

UTF-8编码的字符串在给定的字节位置上可以有0x00到0xff之间的大多数值(尽管一些特定的组合不被允许,参见http://en.wikipedia.org/wiki/UTF-8和八位字节值C0、C1、F5到FF从未出现)。

如果你要通过ASCII流等不支持二进制数据的通道进行传输,则需要适当地进行编码。Base64得到广泛支持,并且肯定会解决这个问题,尽管它并不完全有效,因为它使用了一个包含64个字符的空间来编码数据,而ASCII则允许128个字符的空间。

有一个sourceforge项目提供了base91编码,它更加高效地利用空间,同时避免了非可打印字符http://base91.sourceforge.net/


1
我认为你的第一句话不正确。序列11111110只能出现在七个单位的序列中,我认为这并没有被指定,而据我所知,11111111永远不可能出现。(它怎么可能出现呢?也许在超过七个代码单元的假设扩展中?) - Kerrek SB
你可以在ASCII或UTF-8通道上使用base-128,这甚至更有效:https://dev59.com/8G865IYBdhLWcg3wKLNP#3956975 - Janus Troelsen
你的第一句话是不正确的。根据《RFC 3629》(2003年11月发布的互联网标准),第2页上指出:"八位字节值C0、C1、F5到FF永远不会出现"。 - user824425
@Rhymoid:谢谢,我之前不知道这个。你有什么想法吗?我已经相应地更新了我的答案。 - Eric J.
2
@EricJ。C0和C1是无效的,因为它们是过长的UTF-8序列的一部分(由于其安全影响而被禁止;例如,如果允许,序列[C0 80]将编码U+0000),F5到FD是无效的,因为它们编码了无效的代码点(最高有效代码点是U+10FFFF,使所有序列长度最多为4个八位字节),FE和FF在UTF-8中从未被允许。 - user824425

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接