ChatGPT解决这个技术问题 Extra ChatGPT

UTF-8 和 UTF-16 的区别?

UTF-8 和 UTF-16 的区别?为什么我们需要这些?

MessageDigest md = MessageDigest.getInstance("SHA-256");
String text = "This is some text";

md.update(text.getBytes("UTF-8")); // Change this to "UTF-16" if needed
byte[] digest = md.digest();
jon skeet 有一篇关于编码的好文章....csharpindepth.com/Articles/General/Unicode.aspx

S
Sergei Tachenov

我相信网上有很多关于这方面的好文章,但这里有一个简短的总结。

UTF-8 和 UTF-16 都是可变长度编码。但是,在 UTF-8 中,一个字符可能占用最少 8 位,而在 UTF-16 中,字符长度从 16 位开始。

主要的 UTF-8 优点:

基本的 ASCII 字符,如数字、没有重音的拉丁字符等,占用一个字节,这与 US-ASCII 表示相同。这样,所有 US-ASCII 字符串都变为有效的 UTF-8,这在许多情况下提供了不错的向后兼容性。

没有空字节,允许使用以空字符结尾的字符串,这也引入了大量的向后兼容性。

UTF-8 独立于字节顺序,因此您不必担心 Big Endian / Little Endian 问题。

主要的 UTF-8 缺点:

许多常见字符的长度不同,这会减慢按代码点进行索引的速度,并且会严重地计算代码点计数。

即使字节顺序无关紧要,有时 UTF-8 仍然具有 BOM(字节顺序标记),用于通知文本以 UTF-8 编码,并且即使文本仅包含 ASCII 字符也会破坏与 ASCII 软件的兼容性. Microsoft 软件(如记事本)特别喜欢将 BOM 添加到 UTF-8。

主要的 UTF-16 优点:

BMP(基本多语言平面)字符,包括拉丁文、西里尔文、大多数中文(PRC 强制支持 BMP 之外的一些代码点),大多数日文可以用 2 个字节表示。如果文本不包含补充字符,这会加快索引和计算代码点计数。

即使文本有补充字符,它们仍然由成对的 16 位值表示,这意味着总长度仍然可以被 2 整除,并且允许使用 16 位 char 作为字符串的原始组件。

主要的 UTF-16 缺点:

US-ASCII 字符串中有很多空字节,这意味着没有以空结尾的字符串和大量浪费的内存。

在许多常见情况下(尤其是在美国/欧盟/使用西里尔字母的国家/以色列/阿拉伯国家/伊朗和许多其他国家)中,将其用作固定长度编码“大部分都有效”,通常会导致无法支持的地方中断支持。这意味着程序员必须了解代理对并在重要的情况下正确处理它们!

它是可变长度的,因此计数或索引代码点的成本很高,尽管低于 UTF-8。

一般来说,UTF-16 通常更适合内存中的表示,因为 BE/LE 在那里不相关(只使用本机顺序)并且索引更快(只是不要忘记正确处理代理对)。另一方面,UTF-8 非常适合文本文件和网络协议,因为不存在 BE/LE 问题,并且空终止通常会派上用场,而且兼容 ASCII。


UTF16 上仅缺少 BE/LE 部分 :) UTF-8 有另一个缺点,它可能会产生比 UTF16 更长的输出
是的,我忘记了 BE/LE。不过,这没什么大不了的,尤其是对于内存使用。只有在涉及三字节字符时,UTF-8 才会产生更长的输出,但这意味着主要是中文和日文。另一方面,如果文本包含大量 US-ASCII 字符,则可能会生成较短的输出,因此是否不利取决于特定情况。
我什至没有想到提到 utf-8 的直接 pro,长度更短。关于 utf-8 的较长输出,出于某种原因,它是“可能”,但如果目标位于远东,则默认编码应为 utf-16。至于例子 md.update(text.getBytes("UTF-8"));编码无关紧要,因为哈希在两种情况下都是稳定的。
将字符串转换为字节数组的最快方法就是这样,作为示例发布
你说字符在 UTF-8 中有不同的长度,所以它会减慢索引和计算长度,但我怀疑 UTF-16 中的字符也有不同的长度,UTF-16 的索引和计算长度是否应该更快?
J
Jon Schneider

它们只是表示 Unicode 字符的不同方案。

两者都是可变长度的 - UTF-16 对包含大多数常用字符的基本多语言平面 (BMP) 中的所有字符使用 2 个字节。

UTF-8 对 BMP 中的字符使用 1 到 3 个字节,对于当前 Unicode 范围 U+0000 到 U+1FFFFF 中的字符最多使用 4 个字节,并且如果有必要的话可以扩展到 U+7FFFFFFF...但值得注意的是,所有 ASCII 字符均以单个字节表示。

出于消息摘要的目的,您选择其中的哪一个并不重要,只要尝试重新创建摘要的每个人都使用相同的选项。

有关 UTF-8 和 Unicode 的更多信息,请参阅 this page

(请注意,所有 Java 字符都是 BMP 中的 UTF-16 代码点;要表示 U+FFFF 以上的字符,您需要在 Java 中使用代理对。)


B
Basil Bourque

安全性:仅使用 UTF-8

UTF-8 和 UTF-16 的区别?为什么我们需要这些?

UTF-16 的实现中至少存在几个安全漏洞。见Wikipedia for details

CVE-2008-2938

CVE-2012-2135

WHATWGW3C 具有 now declared,只有 UTF-8 可以在 Web 上使用。

当专门使用 UTF-8 时,此处概述的 [安全] 问题就会消失,这是现在所有事物的强制编码的众多原因之一。

其他团体也这么说。

因此,虽然 UTF-16 可能会继续在 Java 和 Windows 等系统内部使用,但您过去可能在数据文件、数据交换等方面看到的 UTF-16 很少使用,可能会完全消失。


b
bestsss

这与 UTF-8/16 无关(通常,虽然它确实转换为 UTF16 并且 BE/LE 部分可以用单行设置),但下面是将 String 转换为 byte[] 的最快方法。例如:完全适合所提供的情况(哈希码)。 String.getBytes(enc) 相对较慢。

static byte[] toBytes(String s){
        byte[] b=new byte[s.length()*2];
        ByteBuffer.wrap(b).asCharBuffer().put(s);
        return b;
    }

V
Venkateswara Rao

区分 UTF-8 和 UTF-16 的简单方法是确定它们之间的共性。

除了为给定字符共享相同的 unicode 编号外,每个字符都有自己的格式。

UTF-8 尝试用一个字节(如果是 ASCII)来表示给字符的每个 unicode 数字,否则 2 个两个字节,否则 4 个字节等等......

UTF-16 尝试表示,每个 unicode 数字都以两个字节开头。如果两个字节不够用,则使用 4 个字节。如果这还不够,则使用 6 个字节。

理论上,UTF-16 更节省空间,但实际上 UTF-8 更节省空间,因为大多数用于处理的字符(98% 的数据)是 ASCII 和 UTF-8 尝试用单字节和 UTF-16 表示它们尝试用 2 个字节来表示它们。

此外,UTF-8 是 ASCII 编码的超集。因此,每个需要 ASCII 数据的应用程序也将被 UTF-8 处理器接受。这不适用于 UTF-16。 UTF-16 无法理解 ASCII,这是采用 UTF-16 的一大障碍。

另一点需要注意的是,到目前为止,所有 UNICODE 最多可以容纳 4 个字节的 UTF-8(考虑到世界上所有的语言)。这与 UTF-16 相同,与 UTF-8 ( https://stackoverflow.com/a/8505038/3343801 ) 相比并没有真正节省空间

因此,人们尽可能使用 UTF-8。