一个Unicode字符占用多少字节?


239

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

我假设一个Unicode字符可以包含任何语言的所有可能字符-我正确吗?那么每个字符需要多少个字节?

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

我阅读了有关UnicodeWikipedia文章,但对我来说却很难。我期待看到一个简单的答案。



15
抱歉,没有简单的答案。我发现整个事情有点混乱。Unicode被标为使用两个字节并能够表示所有字符,但事实证明,两个字节还不够。
乔纳森·伍德

12
“简单答案”:Unicode字符占用1-4个字节。Unicode涵盖了许多语言,但不是全部。上次查看时,例如Klingon不是正式的Unicode字符集。
Peter G.

9
克林贡不是Unicode标准本身的一部分,不是。它改用Uniode的专用区(U + F8D0-U + F8FF)。
雷米·勒博

1
救世主问题-谢谢。我的情况是通过兼容SCORM 1.2的LMS存储数据... SCORM 1.2'cmi.suspend_data'的标准是4096字节的数据,以前的开发人员认为这意味着我们可以存储4096个字符。噢,他错了-我刚刚发现了为什么我们的书签在长期课程中会失败。所以现在我知道了,因为我们使用的是UTF-8,所以每个字符占用4个字节,因此我们可以得到1024个字符。
danjah 2011年

Answers:


147

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

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

Unicode本身是一个映射,它定义代码点,而代码点是一个数字,通常与一个字符关联。我之所以这样说,通常是因为存在诸如组合字符之类的概念。您可能熟悉重音或变音符号。这些字符可以与另一个字符(例如a或)一起使用u以创建新的逻辑字符。因此,一个字符可以包含1个或多个代码点。

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

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


1
好。那么,在一个给定的代码点中代表一个给定字符的字节数是多少?例如,不间断的空间。
Nicolas Barbulesco,2015年

当在UTF8数组上编写strlen(),substr()和其他字符串操作函数时,这些组合字符使程序员的生活陷入困境。这类工作永远不会完成,并且总是会出现问题。
Nulik

我编写了一个演示,演示了用每种编码解释的Windows-1252,UTF8和UTF8-BOM编码文件,并比较了结果之间的相等性:github.com/vladyrn/encodings_demo
Vlad

195

奇怪的是,没有人指出如何计算占用一个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个字节,具体取决于第一个字节,这将表明它将占用多少字节。


8
我相信4字节字符的最大十六进制值是0xF7(而不是0xF4)。
DJPJ

非常感谢!我只是通过IETF标准进行控制,而我却没有找到有关编码的任何信息,而且我正在阅读的文章没有足够详细地说明使用多少位来表示尾随代码的数量每个“字符”的得分。
MarcusJ

1
现在,这是我在“新成员简介”备忘单的第二页,以及前两个有趣的评论
Cee McSharpface

1
0xF4不是错误,而是澄清。Unicode代码点的范围是0-0x10ffff,因此最后一个代码点被编码为F4 8F BF BF。
弗雷迪亚诺·齐格里奥

38

我知道这个问题很旧,并且已经有一个可以接受的答案,但是我想提供一些示例(希望它对某人有用)。

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

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

Unicode字符需要多少个字节?

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

我假设一个Unicode字符可以包含任何语言的所有可能字符-我正确吗?

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

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

与您的第二个问题相同。

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

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

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

    • 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 AE
    • U + 1337 ETHIOPIC SYLLABLE 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 AC
      • 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统一IDEOGRAPH-8089:
      • 编号:32905
      • UTF-8:E8 82 89
      • UTF-16:80 89
    • U + 1F4A9装扮成POO: 💩
      • 编号: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

好吧,我被带走了...

有趣的事实:


UTF-16中的代码单元为16位宽。您在中间显示了一个空格,这会产生误导。©的UTF-16表示应00A9改为而不是00 A9(它将是UTF-16BE)。
罗兰·伊利格

有什么不同?不代表大端吗?他以大端字节序编写,因此以大端字节UTF-16编写的文件将与UTF-16BE相同,对吗?
HappyPandaFace

6
更正:1)ASCII是7位,字节是8位,因此它远远超过一半。2)Unicode确实定义了如何编码代码点。UTF-8,UTF-16和UTF-32在Unicode标准中定义。
乔纳森·罗森

3
@JonathanRosenne我认为他/他的意思是仅使用8位表示的可能值的一半,而不是使用一半的位。
阿里兹·洛佩兹 Aritz Lopez)

2
我真的很喜欢这些例子。他们强调了例如为什么人们可能更喜欢UTF-16而不是UTF-8。不同软件的开发人员可以根据更有可能使用Unicode字符来选择不同的编码。例如,在中国/日本,UTF-16(2字节)比UTF-8更有意义,因为相同的字符通常需要两倍的字节才能以UTF-8进行编码
麦克

29

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

现在,您需要使用字节(即)来表示此代码点character encodingUTF-8, UTF-16, UTF-6是表示这些字符的方法。

UTF-8是多字节字符编码。字符可以具有1到6个字节(目前可能不需要其中的某些字节)。

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

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


10
Unicode是21位代码集,4个字节足以表示UTF-8中的任何Unicode字符。UTF-16使用代理来表示BMP(基本多语言平面)之外的字符;它需要2或4个字节来表示任何有效的Unicode字符。UCS-2是UTF-16的仅16位变体,不支持BMP之外的替代字符或字符。
乔纳森·勒夫勒

1
你是对的。UTF-8原始的6个字节可容纳32位。我实际上不想让事情复杂化,因为他已经与wiki文档混淆了:)
Zimbabao 2011年

3
该答案指出UTF-16无法编码BMP代码点。这是不正确的,因为可以使用代理对在UTF-8中对它们进行编码。(您必须考虑过时的UCS-2,在Unicode 2.0推出之前,它仅对16位代码点进行编码。)而且,Java不太使用UTF-16,它在代码点处使用了其修改形式。 0编码不同。
rdb 2014年

@rdb-相反。答案说UTF-16代表BMP。
Nicolas Barbulesco,2015年

3
我打错了;我本来想说“非BMP”。答案中的错误是它说UTF-16代表BMP字符,这是不准确的。UTF-16可以对所有unicode字符进行编码-非BMP字符通过代理对进行编码。也许答案者对UCS-2感到困惑。
rdb

17

在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字节编码,直到7FFFFFFF为止。是UTF-32的一半。


8

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

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

(到目前为止)我们可以做的关于大小的唯一编码是UTF-32。即使我认为代码点已为将来的UTF-64做好了准备,每个字符总是有32位:)

使其如此困难的原因至少有两点:

  1. 合成字符,用户决定使用重音符号和基本字符(`A)来代替已使用重音符号(?)的字符实体。
  2. 代码点。编码点是UTF编码所允许编码的方法,它所使用的位数要多于其名称通常所允许的位数。例如,UTF-8指定某些字节本身是无效的,但是当后面跟随有效的连续字节时,将允许描述超出0..255的8位范围的字符。参见示例以下有关UTF-8的Wikipedia文章中和超长编码。
    • 给出的一个很好的例子是€字符(代码点U+20AC可以表示为三字节序列E2 82 AC四字节序列F0 82 82 AC
    • 两者都是有效的,这表明在谈论“ Unicode”而不是关于Unicode的特定编码(例如UTF-8或UTF-16)时,答案有多么复杂。


4

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

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

因此,您想要的简单答案是变化。


3

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

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

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

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



1

从Wiki:

UTF-8是8位可变宽度编码,可最大程度地提高与ASCII的兼容性;

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

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

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

  • 在UTF-8中,每个字符都被编码为1到4个字节(主要编码)
  • 在UTF16中,每个字符被编码为1到两个16位字,并且
  • 在UTF-32中,每个字符都被编码为单个32位字。

1

Unicode是为每个字符提供唯一编号的标准。这些唯一的数字称为code points(这是唯一的代码),用于世界上所有存在的字符(有些字符仍要添加)。

出于不同的目的,您可能需要code points用字节表示(大多数编程语言都用字节表示),这就是Character Encoding开始的地方。

UTF-8UTF-16UTF-32等都是Character Encodings和Unicode代码点在这些编码来表示,以不同的方式。


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

UTF-16具有可变长度,并且其中编码的字符可以占用1或2个字节(8或16位)。这仅表示称为BMP(基本多语言平面)的所有Unicode字符的一部分,几乎可以满足所有情况。Java使用UTF-16字符串和字符编码。

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.