一个 Unicode 字符需要多少个字节?

How many bytes does one Unicode character take?

提问人:nan 提问时间:3/13/2011 最后编辑:Isaac D. Cohennan 更新时间:11/11/2023 访问量:376886

问:

我对编码有点困惑。据我所知,旧的 ASCII 字符每个字符占用一个字节。Unicode 字符需要多少个字节?

我假设一个 Unicode 字符可以包含来自任何语言的所有可能字符 - 我说得对吗?那么每个字符需要多少字节呢?

UTF-7、UTF-6、UTF-16 等是什么意思?它们是 Unicode 的不同版本吗?

我阅读了有关Unicode的维基百科文章,但这对我来说非常困难。我期待看到一个简单的答案。

与字符串 语言无关的 Unicode 编码

评论

1赞 Pizzicato 3/13/2011
en.wikipedia.org/wiki/Comparison_of_Unicode_encodings
18赞 Jonathan Wood 3/13/2011
对不起,没有简单的答案。我发现整个事情有点混乱。Unicode被标榜为使用两个字节并且能够表示所有字符,但事实证明两个字节是不够的。
14赞 Peter G. 3/13/2011
“简单答案”:unicode 字符需要 1-4 个字节。Unicode 涵盖很多语言,但不是全部。例如,上次我看时,克林贡语不是官方的Unicode字符集。
10赞 Remy Lebeau 3/14/2011
克林贡语本身不是Unicode标准的一部分,不是。它使用 Uniode 的私人使用区域 (U+F8D0 - U+F8FF)。
2赞 danjah 6/9/2011
救世主问题 - 谢谢。我的情况是通过符合 SCORM 1.2 的 LMS 存储数据......SCORM 1.2 'cmi.suspend_data' 的标准是 4096 字节的数据,以前的开发人员认为这意味着我们可以存储 4096 个字符。哦,天哪,他错了——我刚刚发现为什么我们的书签在长课程中失败了。所以现在我知道,由于我们使用的是 UTF-8,每个字符需要 4 个字节,因此我们有 1024 个字符。

答:

5赞 Loduwijk 3/13/2011 #1

好吧,我也刚刚在上面拉起了维基百科页面,在介绍部分,我看到“Unicode可以通过不同的字符编码来实现。最常用的编码是 UTF-8(它对任何 ASCII 字符使用一个字节,在 UTF-8 和 ASCII 编码中具有相同的代码值,对于其他字符最多四个字节),现已过时的 UCS-2(每个字符使用两个字节,但不能对当前 Unicode 标准中的每个字符进行编码)”

正如这句话所表明的,你的问题是你假设Unicode是一种单一的字符编码方式。实际上有多种形式的 Unicode,同样,在引号中,其中一种甚至每个字符有 1 个字节,就像您习惯的那样。

所以你想要的简单答案是它各不相同。

8赞 0xC0000022L 3/13/2011 #2

在Unicode中,答案并不容易给出。正如您已经指出的那样,问题在于编码。

给定任何没有变音符号字符的英语句子,UTF-8 的答案将与字符数一样多,而 UTF-16 的答案将是字符数乘以 2。

(截至目前)我们可以对大小做出声明的唯一编码是 UTF-32。在那里,它总是每个字符 32 位,尽管我认为代码点是为未来的 UTF-64 :)准备的

让它如此困难的原因至少有两点:

  1. 组合字符,其中用户决定将重音符号和基本字符 ('A) 组合在一起,而不是使用已重音/变音符号 (À) 的字符实体。
  2. 代码点。码位是 UTF 编码允许编码超过赋予它们名称通常允许的位数的方法。例如,UTF-8 指定某些字节,这些字节本身是无效的,但是当后面跟着一个有效的延续字节时,将允许描述超出 0..255 的 8 位范围的字符。请参阅下面关于 UTF-8 的 Wikipedia 文章中的示例超长编码
    • 这里给出的一个很好的例子是 € 字符(码位可以表示为三字节序列或四字节序列。U+20ACE2 82 ACF0 82 82 AC
    • 两者都是有效的,这表明在谈论“Unicode”而不是 Unicode 的特定编码(例如 UTF-8 或 UTF-16)时,答案是多么复杂。严格来说,正如评论中指出的那样,情况似乎不再如此,甚至是基于我的误解。更新后的维基百科文章的引文如下: 较长的编码称为超长编码,并且不是码位的有效 UTF-8 表示形式。

评论

0赞 Glenn Slayden 9/3/2022
关于“超长”UTF-8 示例(4 个字节而不是 3 个字节),您可以写“...[它们]都是有效的......“,但链接的维基百科文章不再争论;<引用> “较长的编码称为超长编码,不是码位的有效 UTF-8 表示形式。此规则在代码点及其有效编码之间保持一对一的对应关系,以便每个代码点都有唯一的有效编码。“ <引号结束>
0赞 0xC0000022L 9/5/2022
@GlennSlayden感谢您发现它并通知我。我希望现在得到纠正。我宁愿删除我投赞成票的答案,也不愿传播错误/误导性信息。
36赞 Zimbabao 3/13/2011 #3

简单地说,这是一个标准,它为世界上所有字符分配一个数字(称为代码点)(它仍在进行中)。Unicode

现在你需要用字节来表示这个码位,这称为 . 是表示这些字符的方式。character encodingUTF-8, UTF-16, UTF-6

UTF-8是多字节字符编码。字符可以有 1 到 6 个字节(其中一些现在可能不需要)。

UTF-32每个字符有 4 个字节的字符。

UTF-16每个字符使用 16 位,它仅表示称为 BMP 的 Unicode 字符的一部分(对于所有实际目的来说,这就足够了)。Java 在其字符串中使用这种编码。

评论

12赞 Jonathan Leffler 3/13/2011
Unicode 是一个 21 位代码集,4 个字节足以表示 UTF-8 中的任何 Unicode 字符。UTF-16 使用代理项来表示 BMP(基本多语言平面)之外的字符;它需要 2 个或 4 个字节来表示任何有效的 Unicode 字符。UCS-2 是 UTF-16 的唯一 16 位变体,不支持 BMP 之外的代理项或字符。
1赞 Zimbabao 3/13/2011
你是对的。UTF-8 原始版本有 6 个字节来容纳 32 位。我实际上不想让事情复杂化,因为他已经与 wiki 文档混淆了:)
3赞 rdb 8/4/2014
此答案指出 UTF-16 无法对 BMP 码位进行编码。这是不正确的,因为可以使用代理项对进行编码,就像在 UTF-8 中一样。(在Unicode 2.0问世之前,你一定想到了过时的UCS-2,它只编码16位码位。此外,Java 并不完全使用 UTF-16,它使用修改后的形式,其中代码点 0 的编码方式不同。
0赞 Nicolas Barbulesco 1/8/2015
@rdb - 情况恰恰相反。答案是 UTF-16 代表 BMP。
3赞 rdb 1/9/2015
我打错了;我本来想说“非BMP”。答案中的错误在于它说 UTF-16 表示 BMP 字符,这是不准确的。UTF-16 可以对所有 Unicode 字符进行编码——非 BMP 字符通过代理项对进行编码。也许回答者与UCS-2混淆了。
180赞 Logan Capaldo 3/13/2011 #4

你不会看到一个简单的答案,因为没有答案。

首先,Unicode 不包含“来自每种语言的每个字符”,尽管它确实尝试过。

Unicode本身就是一个映射,它定义了代码点,而代码点是一个数字,通常与一个字符相关联。我说通常是因为有组合字符之类的概念。您可能熟悉口音或变音符号等内容。它们可以与另一个字符一起使用,例如 an 或 a 来创建新的逻辑字符。因此,一个字符可以由 1 个或多个代码点组成。au

为了在计算系统中有用,我们需要为这些信息选择一种表示形式。这些是各种 unicode 编码,例如 utf-8、utf-16le、utf-32 等。它们的区别主要在于其代码单元的大小。UTF-32 是最简单的编码,它的代码单元为 32 位,这意味着单个代码点可以舒适地放入代码单元中。其他编码将出现以下情况:一个代码点需要多个代码单元,或者该特定代码点根本无法在编码中表示(例如,UCS-2 存在问题)。

由于组合字符的灵活性,即使在给定的编码中,每个字符的字节数也会因字符和规范化形式而异。这是一种用于处理具有多个表示形式的字符的协议(您可以说哪个是 2 个代码点,其中一个是组合字符或哪个是一个代码点)。"an 'a' with an accent""accented 'a'"

评论

1赞 Nicolas Barbulesco 1/8/2015
还行。那么有多少字节需要在一个给定代码点中表示的一个给定字符?例如,不间断空格。
1赞 Nulik 9/27/2016
组合字符使程序员在 UTF8 数组上编写 strlen()、substr() 和其他字符串操作函数时的生活变得地狱。这种工作永远不会完成,而且总是有问题。
0赞 Vlad Nestorov 8/30/2018
我编写了一个演示,展示了使用每种编码解释的 Windows-1252、UTF8 和 UTF8-BOM 编码文件,并比较了结果之间的相等性:github.com/vladyrn/encodings_demo
0赞 John 11/11/2023
在实践中,没有一种西方语言会为一个字符使用两个代码点。我不确定 CJK,但组合字符是西方人只有在表示星猫表情符号时才能看到的,因为所有使用变音符号的字符也都作为唯一的代码点存在。
0赞 Peter R 12/18/2023
@John 事实并非如此。 这是两个代码点。在十六进制中:["0065", "0301"]
8赞 Nic Cottrell 8/3/2013 #5

有一个很棒的工具可以计算 UTF-8 中任何字符串的字节: http://mothereff.in/byte-counter

更新:@mathias已公开代码:https://github.com/mathiasbynens/mothereff.in/blob/master/byte-counter/eff.js

1赞 ma11hew28 10/10/2013 #6

看看这个Unicode代码转换器。例如,在“0x... 表示法”字段中输入 ,其中 2009 是薄空间的 Unicode 数字,然后单击“转换”。十六进制数(3 个字节)显示在“UTF-8 代码单元”字段中。0x2009E2 80 89

55赞 basic6 5/1/2014 #7

我知道这个问题很老,已经有了一个公认的答案,但我想提供一些例子(希望它对某人有用)。

据我所知,旧的 ASCII 字符每个字符占用一个字节。

右。实际上,由于 ASCII 是 7 位编码,它支持 128 个代码(其中 95 个是可打印的),因此它只使用半个字节(如果这有什么意义的话)。

Unicode 字符需要多少个字节?

Unicode 只是将字符映射到代码点。它没有定义如何对它们进行编码。文本文件不包含 Unicode 字符,而是可能表示 Unicode 字符的字节/八位字节。

我假设一个 Unicode 字符可以包含所有可能的字符 来自任何语言的字符 - 我说得对吗?

不。但差不多。所以基本上是的。但仍然没有。

那么每个字符需要多少字节呢?

与您的第二个问题相同。

UTF-7、UTF-6、UTF-16 等是什么意思?它们是某种Unicode吗 版本?

不,这些是编码。它们定义字节/八位字节应如何表示 Unicode 字符。

举几个例子。如果其中一些无法在浏览器中显示(可能是因为字体不支持它们),请转到(替换为十六进制的代码点)以查看图像。http://codepoints.net/U+1F6AA1F6AA

    • U+0061 拉丁文小写字母 A:a
      • 车次: 97
      • UTF-8:61 个
      • UTF-16:00 61
    • U+00A9 版权标志:©
      • 车次: 169
      • UTF-8:C2 A9
      • UTF-16:00 A9
    • U+00AE注册标志:®
      • 车次: 174
      • UTF-8:C2 AE
      • UTF-16:00 自动曝光
    • U+1337 埃塞俄比亚语音节 PHWA:
      • 编号: 4919
      • UTF-8:E1 8C B7
      • UTF-16:13 37
    • U+2014 EM 短跑:
      • 车次: 8212
      • UTF-8:E2 80 94
      • UTF-16:20 14
    • U+2030 每千个标志:
      • 车次: 8240
      • UTF-8:E2 80 B0
      • UTF-16:20 30
    • U+20AC 欧元符号:
      • 车次: 8364
      • UTF-8:E2 82 交流
      • UTF-16:20 交流电
    • U+2122 商标标志:
      • 编号: 8482
      • UTF-8:E2 84 A2
      • UTF-16:21 22
    • U+2603 雪人:
      • 车次: 9731
      • UTF-8:E2 98 83
      • UTF-16:26 03
    • U+260E 黑色电话:
      • 车次: 9742
      • UTF-8:E2 98 8E
      • UTF-16:26 0E
    • U+2614 雨伞:
      • 编号: 9748
      • UTF-8:E2 98 94
      • UTF-16:26 14
    • U+263A 白色笑脸:
      • 车次: 9786
      • UTF-8:E2 98 BA
      • UTF-16:26 个 3A
    • U+2691 黑旗:
      • 车次: 9873
      • UTF-8:E2 9A 91
      • UTF-16:26 91
    • U+269B 原子符号:
      • 车次: 9883
      • UTF-8:E2 9A 9B
      • UTF-16:26 9B
    • U+2708飞机:
      • 编号: 9992
      • UTF-8:E2 9C 88
      • UTF-16:27 08
    • U+271E 阴影白色拉丁十字架:
      • 编号: 10014
      • UTF-8:E2 9C 9E
      • UTF-16:27 1E
    • U+3020 邮政标记正面:
      • 车次: 12320
      • UTF-8:E3 80 A0
      • UTF-16:30 20
    • U+8089 CJK统一表意文字-8089:
      • 车次: 32905
      • UTF-8:E8 82 89
      • UTF-16:80 89
    • U+1F4A9 一堆便便:💩
      • 车次: 128169
      • UTF-8:F0 9F 92 A9
      • UTF-16:D8 3D DC A9
    • U+1F680火箭:🚀
      • 车次: 128640
      • UTF-8:F0 9F 9A 80
      • UTF-16:D8 3D DE 80

好吧,我得意忘形了......

趣闻:

评论

0赞 Roland Illig 11/26/2016
UTF-16 中的代码单元为 16 位宽。你向他们展示了中间的空格,这是误导性的。的 UTF-16 表示©应该是 而不是(这将是 UTF-16BE)。00A900 A9
0赞 Grifball 6/1/2017
有什么区别?BE不代表大端序吗?他用大端写成,所以用大写端写成的文件 UTF-16 和 UTF-16BE 是一样的,对吧?
10赞 Jonathan Rosenne 8/3/2017
更正:1)ASCII是7位,一个字节是8位,所以它远远超过一半。2) Unicode 确实定义了如何对码位进行编码。UTF-8、UTF-16 和 UTF-32 在 Unicode 标准中定义。
7赞 Aritz Lopez 5/28/2018
@JonathanRosenne我认为他/她的意思是它只使用了 8 位表示的可能值的一半,而不是它使用了一半的位。
4赞 mike 1/31/2019
我真的很喜欢这些例子。例如,它们强调了为什么人们可能更喜欢 UTF-16 而不是 UTF-8。不同软件的开发人员可能会根据更有可能使用的 Unicode 字符来选择不同的编码。例如,在中国/日本,UTF-16(2 字节)对他们来说比 UTF-8 更有意义,因为相同的字符通常需要两倍的字节才能以 UTF-8 编码
261赞 paul.ago 10/26/2015 #8

奇怪的是,没有人指出如何计算一个Unicode字符需要多少字节。以下是 UTF-8 编码字符串的规则:

Binary    Hex          Comments
0xxxxxxx  0x00..0x7F   Only byte of a 1-byte character encoding
10xxxxxx  0x80..0xBF   Continuation byte: one of 1-3 bytes following the first
110xxxxx  0xC0..0xDF   First byte of a 2-byte character encoding
1110xxxx  0xE0..0xEF   First byte of a 3-byte character encoding
11110xxx  0xF0..0xF7   First byte of a 4-byte character encoding

所以快速的答案是:它需要 1 到 4 个字节,具体取决于第一个字节,这将指示它将占用多少字节。

评论

11赞 DJPJ 9/22/2016
我相信 4 字节字符的最大十六进制值是 0xF7(不是 0xF4)。
1赞 MarcusJ 9/27/2016
非常感谢!我只是通过 IETF 标准进行 control+f'ing,我没有找到任何关于编码的内容,而且我正在阅读的文章没有足够详细地说明使用多少位来表示每个“字符”的尾随码位数。
1赞 Cee McSharpface 12/15/2017
现在,这是我的“新团队成员介绍”备忘单的第二页,以及搞笑的前两条评论
3赞 Frediano Ziglio 12/2/2019
0xF4不是错误,而是澄清。Unicode 代码点在 0-0x10ffff 范围内,因此最后一个代码点编码为 F4 8F BF BF。
1赞 Chris 12/30/2020
@DJPJ 原则上是正确的,但 UTF-8 不会使用所有可用空间,以便与 UTF-16 兼容。
3赞 prewett 7/13/2016 #9

对于 UTF-16,如果字符以 0xD800 或更大开头,则需要四个字节(两个代码单元);这样的角色被称为“代理对”。更具体地说,代理对的形式为:

[0xD800 - 0xDBFF]  [0xDC00 - 0xDFF]

其中 [...] 表示具有给定范围的双字节代码单元。任何 <= 0xD7FF 都是一个代码单元(两个字节)。任何 >= 0xE000 都是无效的(可以说,BOM 标记除外)。

参见 http://unicodebook.readthedocs.io/unicode_encodings.html,第 7.5 节。

23赞 John 8/27/2016 #10

在 Unicode 中,每个字符都由一个从 0 到 0x10FFFF 的整数表示。在 32 位整数中天真地执行此操作称为 UTF-32 编码。为了减少浪费,UTF-8 和 UTF-16 是需要较少空间的编码,用于较低的代码点。

请注意,在实现中所谓的 UTF-16 通常实际上只是 UCS2:UTF-16 可以容纳 32 位的代码点子集。

存储要求如下。

在 UTF-8 中:

1 byte:       0 -     7F  (ASCII)
2 bytes:     80 -    7FF  (all European plus some Middle Eastern)
3 bytes:    800 -   FFFF  (multilingual plane incl. the top 1792 and private-use)
4 bytes:  10000 - 10FFFF

在 UTF-16 中:

2 bytes:      0 -   D7FF  (multilingual plane except the top 1792 and private-use)
4 bytes:   D800 - 10FFFF

在 UTF-32 中:

4 bytes:      0 - 10FFFF

根据定义,10FFFF 是最后一个 unicode 代码点,之所以这样定义,是因为它是 UTF-16 的技术限制。

它也是 UTF-8 可以以 4 字节编码的最大码位,但 UTF-8 编码背后的想法也适用于 5 字节和 6 字节编码,以覆盖码位直到 7FFFFFFFF,即。UTF-32 的一半。

1赞 chikitin 11/25/2019 #11

来自维基:

UTF-8,一种 8 位可变宽度编码,可最大限度地兼容 ASCII;

UTF-16,一种 16 位可变宽度编码;

UTF-32,一种 32 位固定宽度编码。

这是三种最流行的不同编码。

  • 在 UTF-8 中,每个字符被编码为 1 到 4 个字节(主要编码)
  • 在 UTF16 中,每个字符被编码为 1 到 2 个 16 位字和
  • 在 UTF-32 中,每个字符都编码为单个 32 位字。
4赞 Giorgi Tsiklauri 6/17/2020 #12

Unicode是一个标准,它为每个字符提供唯一的编号。这些唯一的数字被称为 s(这只是唯一的代码)世界上存在的所有字符(有些字符仍有待添加)。code point

出于不同的目的,您可能需要用字节来表示(大多数编程语言都这样做),这就是发挥作用的地方。code pointsCharacter Encoding

UTF-8、 等都是 ,Unicode 的码位以不同的方式在这些编码中表示。UTF-16UTF-32Character Encodings


UTF-8编码具有可变宽度的长度,其中编码的字符可以占用 1 到 4 个字节(包括 1 到 4 个字节);

UTF-16具有可变长度,其中编码的字符可以采用 1 或 2 个字节(即 8 位或 16 位)。这只代表了所有称为BMP(基本多语言平面)的Unicode字符的一部分,对于几乎所有情况来说都足够了。Java 对其字符串和字符使用编码;UTF-16

UTF-32具有固定长度,每个字符正好占用 4 个字节(32 位)。