Unicode的基础是什么,为什么需要UTF-8或UTF-16?我在谷歌上进行了研究并在这里搜索过,但对我来说不太清楚。
在VSS中进行文件比较时,有时会出现两个文件具有不同UTF的消息。为什么会这样?
请用简单的语言解释。
Unicode的基础是什么,为什么需要UTF-8或UTF-16?我在谷歌上进行了研究并在这里搜索过,但对我来说不太清楚。
在VSS中进行文件比较时,有时会出现两个文件具有不同UTF的消息。为什么会这样?
请用简单的语言解释。
在(不太)早期,只有ASCII。这还好,因为所需的仅是一些控制字符、标点符号、数字和像本句中的字母。不幸的是,当今奇怪的全球互联和社交媒体世界是没有预见到的,因此在同一文档中看到英语、العربية、汉语、עִבְרִית、ελληνικά和ភាសាខ្មែរ并不太罕见(希望我没有破坏任何旧浏览器)。
但出于论证的目的,假设Joe Average是一名软件开发人员。他坚持认为他只需要英语,因此只想使用ASCII。对于用户Joe来说这可能没问题,但对于软件开发人员Joe来说就不行了。大约一半的世界人口使用非拉丁字符,使用ASCII可以说是不考虑这些人,而且他正在关闭他的软件对一个庞大而增长的经济体。
因此,需要一个包含所有语言的全面字符集。于是Unicode应运而生。它为每个字符分配一个称为码点的唯一编号。Unicode相对于其他可能的字符集的优点之一是,前256个代码点与ISO-8859-1和ASCII完全相同。此外,绝大多数常用字符只需用两个字节表示,位于基本多文种平面(BMP)区域内。现在需要一个字符编码来访问这个字符集,正如问题所问,我将专注于UTF-8和UTF-16。那么在这些编码中,多少字节可以访问哪些字符?
值得一提的是,不在BMP中的字符包括古代文字、数学符号、音乐符号和更罕见的Chinese,Japanese和Korean(CJK)字符。
如果您主要使用ASCII字符,则UTF-8肯定更节省内存。但是,如果您主要使用非欧洲脚本,则使用UTF-8比UTF-16少高达1.5倍的内存效率。当处理大量文本时,例如大型网页或冗长的Word文档,这可能会影响性能。
1
,以避免与ASCII字符冲突。字符计数: Unicode 中存在组合字符。例如,代码点 U+006E(n)和 U+0303(一个组合的波浪符)形成了 ñ,但代码点 U+00F1 形成了 ñ。它们应该看起来相同,但是简单的计数算法将返回第一个示例的 2,而后者为 1。这不一定是错误的,但也可能不是期望的结果。
比较相等性: A、А 和 Α 看起来相同,但它们分别是拉丁字母、西里尔字母和希腊字母。还有像 C 和 Ⅽ 这样的情况。一个是字母,另一个是罗马数字。此外,我们还需要考虑组合字符。有关更多信息,请参见Duplicate characters in Unicode。
代理对: 这些在 Stack Overflow 上经常出现,因此我将提供一些示例链接:
简单解释:
计算机读取字节,人们读取字符,因此我们使用编码标准将字符映射到字节。 ASCII是第一个广泛使用的标准,但仅涵盖拉丁字符(每个字符使用7位表示最多可以表示128个不同的字符)。 Unicode是一个旨在覆盖世界上所有可能字符的标准(最多可以容纳1,114,112个字符,即每个字符最多使用21位表示。当前的Unicode 8.0总共规定了120,737个字符)。
主要的区别在于ASCII字符可以适配一个字节(8位),但大多数Unicode字符不行。因此需要使用编码格式/方案(如UTF-8和UTF-16),字符模型如下:
每个字符都有一个编号,从0到1,114,111(十六进制:0-10FFFF)称为代码点。
一个编码形式将一个码位映射到一个码元序列。一个码元是你想要字符在内存中组织的方式,可以是8位、16位等。UTF-8使用1到4个8位的码元,而UTF-16使用1到2个16位的码元,可以覆盖最大21位的整个Unicode。码元使用前缀以便识别字符边界,而更多的码元表示更多占用位数的前缀。因此,尽管UTF-8仅使用一个字节来表达拉丁文字母,但需要三个字节来表达基本多文种平面内的后来的脚本,而UTF-16对于所有这些脚本都使用两个字节。这是它们的主要区别。字符:π
码位:U+03C0
编码形式(码元):
UTF-8:CF 80
UTF-16:03C0
编码方案(字节):
UTF-8:CF 80
UTF-16BE:03 C0
UTF-16LE:C0 03
提示:一个十六进制数字表示四个比特,所以两位的十六进制数表示一个字节。
还可以看看维基百科上的平面地图,了解字符集布局。
文章 《每个程序员绝对需要知道的有关编码和字符集的知识,以便处理文本》 解释了所有详细信息。
如果你使用UTF8编码方式向一个4字节大小的缓冲区中写入符号あ
,那么你的二进制数据将会长成这样:
00000000 11100011 10000001 10000010
如果你使用UTF16编码方式向一个4字节大小的缓冲区中写入同样的符号あ
,那么你的二进制数据将会长成这样:
00000000 00000000 00110000 01000010
可以看到,根据内容所用的语言不同,它会影响内存的使用情况。
例如:对于这个特定的符号あ
,使用UTF16编码更高效,因为我们可以利用多余的2个字节来存储下一个符号。但这并不意味着你必须在日语字母中使用UTF16。
现在,如果你想读取上述字节,你必须知道它是以哪种编码方式写入的,并正确地解码它。
例如:如果你将这个二进制数据00000000 11100011 10000001 10000010解码成UTF16编码方式,你将得到臣
而不是あ
注意: 编码和Unicode是两个不同的概念。Unicode是一个大的(表格),其中每个符号都映射到一个唯一的代码点。例如:あ
符号(字母)有一个(代码点):30 42(十六进制)。而编码则是一种算法,将符号转换为更适合存储在硬件中的方式。
30 42 (hex) - > UTF8 encoding - > E3 81 82 (hex), which is above result in binary.
30 42 (hex) - > UTF16 encoding - > 30 42 (hex), which is above result in binary.
最初,Unicode旨在具有固定宽度的16位编码(UCS-2)。像Java和Windows NT这样的Unicode早期用户,构建了围绕16位字符串的库。
后来,Unicode的范围扩展到包括历史字符,这需要超过16位编码所支持的65,536个代码点。为了让那些使用UCS-2的平台可以表示额外的字符,引入了UTF-16编码。它使用“代理对”来表示补充平面上的字符。
同时,很多旧软件和网络协议都在使用8位字符串。UTF-8的出现是为了使这些系统可以支持Unicode而不必使用宽字符。它向后兼容7位ASCII。
Unicode是一种标准,将所有语言中的字符映射到一个叫做代码点的特定数值。它之所以这样做是因为它允许使用相同的代码点集合来实现不同的编码。
UTF-8和UTF-16就是这样的两种编码方式。它们将代码点作为输入,并使用某些明确定义的公式对其进行编码以生成编码后的字符串。
选择特定的编码取决于您的需求。不同的编码具有不同的内存要求,而且根据您将要处理的字符,您应该选择使用最少字节序列来编码这些字符的编码。
有关Unicode、UTF-8和UTF-16的更详细信息,请参阅此文章:
为什么要使用Unicode?因为ASCII只有127个字符。从128到255的字符在不同的国家是不同的,这就是为什么会有代码页。所以他们说:让我们有多达1114111个字符。
那么如何存储最高代码点呢?你需要使用21位来存储它,因此你将使用一个DWORD,有32位和11位浪费。所以如果你使用一个DWORD来存储Unicode字符,这是最简单的方法,因为你DWORD中的值完全匹配代码点。
但是DWORD数组当然比WORD数组大,甚至比BYTE数组还要大。这就是为什么不仅有UTF-32,还有UTF-16的原因。但是UTF-16意味着一个WORD流,而一个WORD有16位,所以最高代码点1114111怎么能适应一个WORD呢?它不能!
所以他们把所有高于65535的东西放入了一个称为替代对的DWORD中。这样的替代对是两个WORDS,并且可以通过查看前6位来检测。
那么UTF-8呢?它是一个字节数组或字节流,但最高代码点1114111怎么能适应一个字节呢?它不能!好吧,他们也放入了一个DWORD,或者可能是一个WORD,对吗?几乎对了!
他们发明了utf-8序列,这意味着每个代码点高于127必须被编码为2字节、3字节或4字节序列。哇!但是我们如何检测这样的序列呢?嗯,一切都在127之前都是ASCII并且是一个单独的字节。以110开头的是两字节序列,以1110开头的是三字节序列,以11110开头的是四字节序列。这些所谓的“起始字节”的剩余位属于代码点。
现在根据序列,必须跟随以下字节。接下来的字节以10开头,其余位是6位有效载荷位,并属于代码点。连接起始字节和后续字节的有效载荷位,就得到了代码点。这就是UTF-8的所有魔力。