UTF-8、UTF-16和UTF-32之间有什么区别?

我知道它们都将存储Unicode,并且每个都使用不同的字节数来表示一个字符。选择一个比另一个有优势吗?


简而言之:

UTF-8: Variable-width encoding, backwards compatible with ASCII. ASCII characters (U+0000 to U+007F) take 1 byte, code points U+0080 to U+07FF take 2 bytes, code points U+0800 to U+FFFF take 3 bytes, code points U+10000 to U+10FFFF take 4 bytes. Good for English text, not so good for Asian text. UTF-16: Variable-width encoding. Code points U+0000 to U+FFFF take 2 bytes, code points U+10000 to U+10FFFF take 4 bytes. Bad for English text, good for Asian text. UTF-32: Fixed-width encoding. All code points take four bytes. An enormous memory hog, but fast to operate on. Rarely used.

长:参见维基百科:UTF-8, UTF-16和UTF-32。


UTF-8为变量1 ~ 4字节。 UTF-16是可变的2或4字节。 UTF-32是固定的4字节。


UTF-8在ASCII字符代表文本块中的大部分字符的情况下具有优势,因为UTF-8将这些字符编码为8位(像ASCII一样)。它的另一个优点是只包含ASCII字符的UTF-8文件具有与ASCII文件相同的编码。

在ASCII不占主导地位的情况下,UTF-16更好,因为它主要每个字符使用2个字节。UTF-8将开始对高阶字符使用3个或更多字节,而UTF-16对大多数字符仅使用2个字节。

UTF-32将在4字节内涵盖所有可能的字符。这使得它非常臃肿。我想不出使用它有什么好处。


如前所述,差异主要在于底层变量的大小,在每种情况下,它们都会变大以允许表示更多字符。

然而,字体、编码和其他东西都非常复杂(没有必要?),所以需要一个大链接来填充更多细节:

http://www.cs.tut.fi/~jkorpela/chars.html#ascii

不要期望理解所有的东西,但是如果你不想在以后遇到问题,尽可能早地学习(或者让别人帮你整理)是值得的。

保罗。


Unicode定义了一个巨大的字符集,为每个图形符号分配一个唯一的整数值(这是一个主要的简化,实际上不是真的,但对于这个问题的目的来说已经足够接近了)。UTF-8/16/32只是编码的不同方式。

简而言之,UTF-32对每个字符使用32位值。这允许他们对每个字符使用固定宽度的代码。

UTF-16默认使用16位,但这只提供了65k个可能的字符,这远远不够完整的Unicode集。所以有些字符使用一对16位的值。

UTF-8默认使用8位值,这意味着前127个值是固定宽度的单字节字符(最高位用于表示这是多字节序列的开始,为实际的字符值留出7位)。所有其他字符编码为最多4个字节的序列(如果内存可用的话)。

这就引出了它的优点。任何ascii字符都与UTF-8直接兼容,因此对于升级遗留应用程序,UTF-8是一个常见而明显的选择。在几乎所有情况下,它也将使用最少的内存。另一方面,你不能保证字符的宽度。它可能是1、2、3或4个字符宽,这使得字符串操作困难。

UTF-32则相反,它使用最多的内存(每个字符都是固定的4字节宽),但另一方面,您知道每个字符都有这个精确的长度,因此字符串操作变得简单得多。您可以简单地根据字符串的字节长度计算字符串中的字符数。你不能用UTF-8这样做。

UTF-16是一种折衷。它让大多数字符适合固定宽度的16位值。所以只要你没有中文符号、音符或其他东西,你可以假设每个字符是16位宽。它比UTF-32使用更少的内存。但在某种程度上,这是“两败俱伤”。它几乎总是比UTF-8使用更多的内存,而且它仍然无法避免困扰UTF-8(变长字符)的问题。

最后,只使用平台支持的内容通常是有帮助的。Windows内部使用UTF-16,因此在Windows上,这是显而易见的选择。

Linux稍有不同,但它们通常使用UTF-8来处理所有与unicode兼容的内容。

简短的回答:所有三种编码都可以编码相同的字符集,但它们将每个字符表示为不同的字节序列。


根据您的开发环境,您甚至无法选择字符串数据类型将在内部使用什么编码。

但是对于存储和交换数据,我总是使用UTF-8,如果你有选择的话。如果您的数据主要是ASCII数据,这将为您提供最少的数据传输量,同时仍然能够编码所有内容。优化最小的I/O是现代机器的发展方向。


在UTF-32中,所有字符都用32位编码。这样做的好处是可以很容易地计算字符串的长度。缺点是对于每个ASCII字符,您会浪费额外的3个字节。

在UTF-8字符有可变长度,ASCII字符编码为一个字节(8位),大多数西方特殊字符编码为两个字节或三个字节(例如€是三个字节),更奇特的字符可以占用四个字节。明显的缺点是,先验你不能计算字符串的长度。但与UTF-32相比,编码拉丁(英语)字母文本所需的字节要少得多。

UTF-16也是可变长度的。字符编码为两个字节或四个字节。我真的不明白这有什么意义。它有可变长度的缺点,但没有像UTF-8那样节省空间的优点。

在这三种语言中,UTF-8显然是传播最广泛的。


我做了一些测试来比较MySQL中UTF-8和UTF-16之间的数据库性能。

更新的速度

utf - 8

utf - 16

插入的速度

删除速度


Unicode是一个标准,关于UTF-x,你可以把它看作是一个技术实现,用于一些实际目的:

UTF-8 - "size optimized": best suited for Latin character based data (or ASCII), it takes only 1 byte per character but the size grows accordingly symbol variety (and in worst case could grow up to 6 bytes per character) UTF-16 - "balance": it takes minimum 2 bytes per character which is enough for existing set of the mainstream languages with having fixed size on it to ease character handling (but size is still variable and can grow up to 4 bytes per character) UTF-32 - "performance": allows using of simple algorithms as result of fixed size characters (4 bytes) but with memory disadvantage


utf - 8

没有字节顺序的概念 每个字符使用1到4个字节 ASCII是一种兼容的编码子集 完全自同步,例如从流中的任何地方删除字节最多只会损坏一个字符 几乎所有的欧洲语言都是用两个字节或更少的字符编码的

utf - 16

必须使用已知的字节顺序进行解析,或者读取字节顺序标记(BOM)。 每个字符使用2或4个字节

utf - 32

每个字符是4个字节 必须使用已知的字节顺序进行解析,或者读取字节顺序标记(BOM)。

UTF-8将是空间效率最高的,除非大多数字符来自CJK(中国、日本和韩国)字符空间。

UTF-32最适合通过字符偏移量随机访问字节数组。


简而言之,使用UTF-16或UTF-32的唯一原因是分别支持非英语和古代脚本。

我想知道为什么有人会选择非utf -8编码,因为它显然对web/编程更有效。

一个常见的误解-加后缀的数字不是它的能力的指示。它们都支持完整的Unicode,只是UTF-8可以用一个字节处理ASCII,所以对CPU和互联网来说更有效/更不容易损坏。

一些不错的阅读:http://www.personal.psu.edu/ejp10/blogs/gotunicode/2007/10/which_utf_do_i_use.html 和http://utf8everywhere.org


我试图在我的博客中给出一个简单的解释。

utf - 32

需要32位(4字节)来编码任何字符。例如,为了使用这个方案来表示“A”字符代码点,你需要用32位二进制数字写65:

00000000 00000000 00000000 01000001 (Big Endian)

如果仔细观察,您会注意到最右边的7位实际上是使用ASCII格式时的相同位。但是由于UTF-32是固定宽度的方案,我们必须附加三个额外的字节。这意味着,如果我们有两个只包含“A”字符的文件,一个是ascii编码的,另一个是UTF-32编码的,它们的大小将分别为1字节和4字节。

utf - 16

许多人认为UTF-32使用固定宽度的32位来表示码位,UTF-16是固定宽度的16位。错了!

在UTF-16中,码位可以用16位或32位表示。所以这个方案是变长编码系统。与UTF-32相比,它的优势是什么?至少对于ASCII,文件的大小不会是原始文件的4倍(但仍然是两倍),所以我们仍然不能向后兼容ASCII。

由于7位足以表示“A”字符,我们现在可以使用2个字节,而不是像UTF-32那样使用4个字节。它看起来是这样的:

00000000 01000001

utf - 8

你猜对了。在UTF-8中,码位可以用32位、16位、24位或8位来表示,作为UTF-16系统,这也是一种变长编码系统。

最后,我们可以用与ASCII编码系统相同的方式来表示“A”:

01001101

一个小例子,UTF-16实际上比UTF-8更好:

考虑中文字母“語”,它的UTF-8编码是:

11101000 10101010 10011110

虽然它的UTF-16编码较短:

10001010 10011110

为了了解这种表达方式以及它是如何解释的,请访问原文。


在阅读完答案后,UTF-32需要一些爱。

C#:

Data1 = RandomNumberGenerator.GetBytes(500_000_000);

sw = Stopwatch.StartNew();
int l = Encoding.UTF8.GetString(Data1).Length;
sw.Stop();
Console.WriteLine($"UTF-8: Elapsed - {sw.ElapsedMilliseconds * .001:0.000s}   Size - {l:###,###,###}");

sw = Stopwatch.StartNew();
l = Encoding.Unicode.GetString(Data1).Length;
sw.Stop();
Console.WriteLine($"Unicode: Elapsed - {sw.ElapsedMilliseconds * .001:0.000s}   Size - {l:###,###,###}");

sw = Stopwatch.StartNew();
l = Encoding.UTF32.GetString(Data1).Length;
sw.Stop();
Console.WriteLine($"UTF-32: Elapsed - {sw.ElapsedMilliseconds * .001:0.000s}   Size - {l:###,###,###}");

sw = Stopwatch.StartNew();
l = Encoding.ASCII.GetString(Data1).Length;
sw.Stop();
Console.WriteLine($"ASCII: Elapsed - {sw.ElapsedMilliseconds * .001:0.000s}   Size - {l:###,###,###}");

UTF-8—经过9.939秒-大小473,752,800

Unicode—消失0.853秒-大小2.5亿

UTF-32—消失3.143秒-大小125,030,570

ASCII—经过2.362秒-大小500,000,000

Utf-32——丢麦克风