UTF-8编码字符的最大字节数是多少?

97

单个UTF-8编码字符的最大字节数是多少?

我将加密以UTF-8编码的字符串的字节,因此需要能够计算出UTF-8编码字符串的最大字节数。

请问有人能够确认单个UTF-8编码字符的最大字节数吗?


2
你确实查看了常见的资源,比如维基百科的UTF-8文章……对吧? - user166390
6
我读了几篇文章,得到了不同的答案......实际上,我对答案是3的印象很深,所以我很高兴自己问了一下。 - Edd
3
我会留下一个YouTube链接,展示Tom Scott的"Characters, Symbols, Unicode miracle"视频:https://goo.gl/sUr1Hf。您将听到和看到所有事物是如何从ASCII字符编码演变到UTF-8的。 - Roy Lee
请参考不实际编码的情况下计算Java字符串UTF-8长度获取计算字符串长度的代码示例。 - Vadzim
4个回答

106
根据RFC3629,每个字符的最大字节数是4,它限制了字符表到U+10FFFF

在UTF-8中,来自U+0000..U+10FFFF范围(UTF-16可访问范围)的字符使用1到4个八位字节序列进行编码。

(原始规范允许超过U+10FFFF的代码点使用长达6个字节的字符编码。)
小于128的代码需要1个字节,下一个1920个字符代码只需要2个字节。除非你使用的是奇特的语言,否则将字符数量乘以4会明显高估字节数量。

8
对于你来说,“神秘语言”是什么?是真实世界中存在的任何语言,还是在不同世界语言之间切换的文本?如果一个UTF-8到字符串函数的开发者进行过度分配并在实际转换后缩小结果,则应该选择2、3或4作为乘数? - Daniel Marschall
2
@rinntech所说的“奇怪语言”是指具有许多高价值Unicode字符的语言(来自此列表底部附近的内容:http://unicode-table.com/en/sections/)。如果必须过度分配,请选择4。您可以进行双重传递,一次查看需要多少字节并进行分配,然后另一次进行编码;这可能比分配大约4倍所需的RAM更好。 - matiu
10
始终试图处理最坏情况:http://www.hacker9.com/single-message-can-crash-whatsapp.html - Evgen Bodunov
24
汉字(CJKV字符)大多占用3个字节(一些罕见或古代的字符占用4个字节),将它们称为神秘的有点牵强(仅中国就占世界人口的近20%……)。 - Tgr
5
为什么之前是6位,现在限制为4位?如果我们继续使用标准,将首字节设为11111111,那么有没有什么阻碍我们使用2^(6*7)个比特空间来表示字符呢? - Aaron Franke
显示剩余9条评论

36

没有更多的上下文,我会说UTF-8字符的最大字节数为

答案:6字节

被接受的答案的作者正确指出了这一点作为“原始规范”。 这在RFC-2279 1中是有效的。 如下面的J. Cocoe所指出的那样,这在2003年的RFC-3629 2中发生了变化,将UTF-8限制为编码21位,可以使用编码方案使用四个字节处理。

如果涵盖所有Unicode,则答案为:4字节

但是,在Java <= v7中,他们谈到了使用UTF-8表示Unicode的最大字节数为3个?这是因为原始的Unicode规范仅定义了基本多语言平面(BMP),即它是Unicode的旧版本或现代Unicode的子集。 因此,如果仅表示原始的Unicode,BMP:3个字节

但是,OP谈到的是反过来的情况。不是从字符到UTF-8字节,而是从UTF-8字节到“字符串”字节表示。也许被接受答案的作者从问题的上下文中得出了这个结论,但这并不一定显而易见,可能会让这个问题的普通读者感到困惑。
从UTF-8到本地编码,我们必须看看“字符串”的实现方式。一些语言,如Python >= 3,将每个字符表示为整数代码点,这允许每个字符使用4个字节= 32位来覆盖我们需要的21个unicode位,有一些浪费。为什么不是准确的21位?因为当它们与字节对齐时,速度更快。一些语言,如Python <= 2和Java,使用UTF-16编码表示字符,这意味着它们必须使用代理对来表示扩展的unicode(不是BMP)。无论哪种方式,最多仍然是4个字节。
回答如果是从UTF-8->本地编码:4个字节
所以,最终结论是,4是最常见的正确答案,所以我们做对了。但是,结果可能会有所不同。

6
“这仍然是当前和正确的规范,按照维基百科”-- 不再是了。在您写下这段话之后不久(4月2日编辑),维基百科的UTF-8文章被更改以澄清6个字节版本不属于当前(2003年)的UTF-8规范。 - J. Cocoe
但是,在Java <= v7中,他们谈论使用UTF-8表示Unicode的最大字节数为3个?这是因为原始的Unicode规范只定义了基本多语言平面。那可能是最初的原因,但这并不是全部。Java使用“修改后的UTF-8”,其中一种修改是它“使用自己的两个三字节格式”而不是“标准UTF-8的四字节格式”(他们的话)。 - J. Cocoe
1
没有分配超过10FFFF(略高于一百万)限制的代码点,许多UTF8实现从未实现超过4个字节的序列(有些只有3个,例如MySQL),因此即使考虑与旧实现的兼容性,我认为将4个字节硬限制为每个代码点是安全的。您只需要确保在输入时丢弃任何无效内容。请注意,matiu建议在可能的情况下计算精确字节长度后再进行分配,这是一个好建议。 - thomasrutter
2
Unicode能够表示多达x10FFFF个代码点。因此,包括0在内,我们可以用以下字节表示:FFFFFF,即2.5个字节或20位。我认为这有点不正确。从0x0到0x10FFFF的码点数量应该是0x110000,可以用1F FFFF或21位表示。0x110000代表了17个平面(每个平面都有0x10000个代码点)。 - neuralmer
2
温馨提示:维基百科不是真正的来源。请查看文章的实际参考资料。 - Nyerguds
显示剩余2条评论

0

支持标准英文字母编码US-ASCII的最大字节数为1。但随着时间的推移,限制文本只使用英语变得越来越不可取或实用。

Unicode旨在表示所有人类语言的字形,以及许多种符号,并具有各种呈现特性。UTF-8是Unicode的一种高效编码方式,尽管仍然偏向英语。UTF-8是自同步的:通过扫描任一方向上的明确定义的位模式,可以轻松地识别字符边界。

虽然每个UTF-8字符的最大字节数为3,以支持仅2字节地址空间的第0平面(BMP,Basic Multilingual Plane),这可以作为某些应用程序中的最小支持,但支持当前所有17个Unicode平面(截至2019年)的最大字节数为4。值得注意的是,许多流行的“表情符号”字符可能位于第16平面,需要4个字节。

但是,这仅适用于基本字符字形。还有各种修饰符,例如使重音出现在前一个字符上,并且还可以将任意数量的代码点链接在一起构建一个复杂的“字形”。因此,在实际的编程中,使用或假设每个字符的固定最大字节数最终可能会导致应用程序出现问题。

这些考虑意味着在处理之前,UTF-8字符字符串不应该像有时候所做的那样被“扩展”为固定长度的数组。相反,应该直接进行编程,使用专门为UTF-8设计的字符串函数。

注意:关于不使用固定宽度的字符数组的段落是我个人的意见。我愿意根据评论进行编辑。 - David Spector
还要注意克林贡语也是Unicode编码,因此它不仅仅是所有人类语言。至于您的建议,最终取决于您正在优化什么以及基准测试告诉您什么。有时,快速地通过已知数量的字节而没有条件逻辑或分支会更快。分支可能会严重影响性能。如果您预处理了它,仍然必须进行分支,但至少较重的计算部分将在连续内存中快速执行而无需零分支。但如果您想优化空间,则不是一个好主意。 - user904963
克林贡语是一种人类语言,意味着它是由马克·奥克兰德和其他人类设计的,以实现人类目的。克林贡语不是外星语言,因为克林贡星球并不存在。至于您对使用六字节数组来处理字符的常见做法的明显辩护,我们将不得不同意不同意见。这样的限制是错误的。 - David Spector
使用UTF编码,最大字节数为4。根据所使用的符号,您可以使用1个字节(例如:带标点的英语)或2个字节(如果您知道没有表情符号、中文、日文等)。如果对文本运行算法多次,则预处理的优势会更加明显。否则,每次运行算法时,都会有一堆分支(尽管CPU的分支检测器会在符号可预测的情况下提供很多帮助)。我没有说预处理更好,只是可能更好,需要进行测试。 - user904963
当使用固定长度数组时,如果您希望编码表情符号(这些天相当流行),则所需的最小字节数为6。在我的编码中,我发现根本不需要使用固定长度数组。您正在尝试做的任何事情都可以通过字节导向编程或通过扫描UTF-8字节来获取实际字符长度来实现。 - David Spector

-1

考虑只是技术上的限制 - 根据当前的UTF8编码方案,最多可以有7个字节跟随。根据规则 - 如果第一个字节不是自包含ASCII字符,则应该具有模式:1(n)0X(7-n),其中n <= 7。

理论上也可能是8个字节,但那么第一个字节就没有零位了。虽然其他方面,如连续字节与前导字节不同(允许错误检测),但我听说11111111字节可能无效,但我不能确定。

最多4个字节的限制很可能是为了与UTF-16兼容,我倾向于认为它已经是一种遗留技术,因为它唯一优越的质量就是处理速度,但仅当字符串字节顺序匹配时(即我们在BOM中读取0xFEFF)。


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