如何确定“最低”可能的编码?

3

场景

您有许多以UTF-16格式存储的XML文件,这些文件存储在数据库或服务器上,空间不是问题。您需要将其中大部分需要作为XML文件传输到其他系统,并尽可能地节省空间。

问题

实际上,只有约10%以UTF-16格式存储的文件需要以UTF-16格式存储,其余可以安全地以UTF-8格式存储。如果我们可以将需要采用UTF-16格式的文件与其他文件采用UTF-8格式的文件区分开来,我们可以在文件系统上节省约40%的空间。

我们尝试过对数据进行压缩,但发现无论采用UTF-16还是UTF-8,我们都可以获得相同的压缩比例,而UTF-8的压缩速度更快。因此,最终如果尽可能多地使用UTF-8保存数据,我们不仅可以在未压缩时节省空间,即使在压缩后,我们仍然可以节省更多的空间,甚至可以通过压缩本身来节省时间。

目标

确定XML文件中是否存在需要UTF-16格式的Unicode字符,以便我们只在必要时使用UTF-16格式。

关于XML文件和数据的一些详细信息

虽然我们控制XML本身的模式,但是从Unicode的角度来看,我们无法控制可以放入值的“字符串”类型,因为源自由提供Unicode数据供我们使用。但是,这种情况很少发生,因此我们不想每次都使用UTF-16仅支持只需要10%时间的东西。

开发环境

我们正在使用带有.NET Framework 4.0的C#。

编辑:解决方案

解决方案只需使用UTF-8。

问题基于我的误解而产生,感谢每个人帮助我纠正。谢谢!


6
这个问题有一些错误的假设,因为任何可以以UTF-16格式存储的文档也可以以UTF-8格式存储,因为这两种格式是双向兼容的。不存在必须使用UTF-16格式存储的文档。 - JSBձոգչ
@Creepy Gnome: 你能具体说明一下什么是不“UTF-8安全”的数据吗? - Matti Virkkunen
@Jon:然而在.NET中,由于char类型是一个16位整数,当迭代字符串时可能会返回代理项。看,那个人说他有一些“非UTF-8安全数据”,我不得不猜测它可能意味着什么:V - Matti Virkkunen
谢谢大家!!!我对UTF的误解显而易见,感谢大家帮助我弄清楚。我将在所有情况下使用UTF-8,并且我们会很好。再次感谢! - Rodney S. Foley
3
UTF-32是处理单个字符最有效的编码方式 - 每个字符(但不是每个字形集群,那里有不同的问题)将适合于一个单元。UTF-16在处理内存中的字符串时效率高,因为绝大多数字符都位于BMP中并与UCS-2兼容(这是Unicode历史的遗留问题,仅支持BMP)。UTF-8向后兼容US-ASCII,在许多传输和存储情况下效率高。它们可以胜任任何工作,但在某些方面具有不同的优势。 - Jon Hanna
显示剩余7条评论
5个回答

7

编辑:我没有意识到你的问题暗示了你认为有一些Unicode字符串不能被安全地编码为UTF-8。这不是事实。以下答案假设你真正想表达的是某些字符串在UTF-8下只是更长(需要更多存储空间)。


我认为甚至不到10%的文件需要以UTF-16格式存储。即使你的XML包含大量中文、日文、韩文或其他UTF-8比UTF-16更大的语言,只有当该语言的文本量超过XML语法时才会成为问题。

因此,我的初步直觉是“在出现问题之前一直使用UTF-8”。这也有助于保持一致性。

如果你有充分的理由相信XML的很大一部分将是东亚语言,那么你就需要关注它。在这种情况下,我会应用一个简单的启发式方法,例如...遍历XML并计算大于U+0800(在UTF-8中占三个字节)的字符数,只有当这个数大于小于U+0080(在UTF-8中占一个字节)的字符数时,才使用UTF-16。


我不同意你的启发式。它应该将那些小于或等于U+007F(UTF-8中的1个八位组)与那些大于或等于U+0800且小于U+10000(UTF-8中的3个八位组)进行比较,因为其他字符在两者之间是相等的(在U+0080到U+07FF之间都是2个八位组,在U+10000及更高处都是4个八位组)。话虽如此,除非非常大量的文档不仅仅是东亚文本,并且这些字符还压倒了低代码点字符,否则我倾向于始终使用UTF-8以获得更简单和一致性。 - Jon Hanna

6

将所有内容编码为UTF-8。UTF-8可以处理任何UTF-16可以处理的内容,并且在XML文档的情况下几乎肯定会更小。唯一一种UTF-8比UTF-16更大的情况是,如果文件主要由BMP之外的字符组成,在最好的情况下(ASCII-spec,其中包括您可以在标准美国104键上输入的每个字符),UTF-8文件将是UTF-16文件大小的一半。

对于所有符号的Unicode编号在U+07FF及以下的字符,UTF-8每个字符需要2个字节或更少,并且对于扩展ASCII代码页中的任何字符,每个字符只需要1个字节;这意味着对于使用拉丁语、希腊语、西里尔语、希伯来语或阿拉伯语字母表的现代语言编写的任何文档,包括代数和国际音标中使用的大多数常见符号,UTF-8的大小至少与UTF-16相等(并且可能远小于UTF-16)。这被称为基本多语言平面,涵盖了亚洲以外的所有官方国家语言的90%以上。

通常情况下,对于主要使用天城文(印地语)、日文、汉语或韩文字母表或任何古代或“神秘”字母表(切诺基语或因纽特语)的文档,UTF-16将为您提供更小的文件,并且在大量使用专业数学、科学、工程或游戏符号的文档中可能更小。如果您正在处理用于印度、中国和日本的本地化文件的XML,则可能会使用UTF-16获得更小的文件大小,但您必须使您的程序足够智能,以知道本地化文件是以这种方式编码的。


为了解释我选择给出这个勾选的原因,因为从技术上讲,所有的答案似乎都是相似和正确的。我并没有完全理解UTF,正如我的问题所示,而这是第一个不仅回答了我真正需要回答的问题,而且还向我解释了原因的答案。因此,我提高了每个人对这个问题有所涉猎的问题,并将勾选给了Keith。我非常感谢所有的帮助和纠正我的人。谢谢大家! - Rodney S. Foley
2
这个答案中存在一个事实错误:基本多文种平面从U+0000到U+FFFF,包括所有现代日常使用的东亚文字,这些文字在UTF-8中每个字符需要3个字节。 - Timwi

5
你永远不需要使用UTF-16代替UTF-8,选择并不涉及“安全性”问题。两种编码都具有相同的可编码字符集。

问题中提到“使用尽可能少的空间非常重要”,而这个回答并没有解决这个问题。 - Timwi
好的,就安全性而言,如果您事先知道需要存储什么,并且有足够的空间进行存储,那么您是安全的。然而,如果数据可以随意更改,并且您的存储空间非常有限,那么您永远不会安全;您可能会用完空间。正是这种混乱的语言分散了注意力,似乎我不是唯一一个在这里受到干扰的人。 - Juho Östman

3

没有必须使用UTF-16编码的文档。任何UTF-16文档都可以编码为UTF-8。理论上,UTF-8可能会比UTF-16更大,但这种情况非常罕见,不值得过多担忧。

将所有内容都编码为UTF-8,不要再担心它了。


1
这并不是非常不可能的事情。对于任何用中文、日语、韩语、印地语、古吉拉特语、缅甸语、泰语、高棉语等书写的文件都是如此。 - Timwi
除非XML标记名称为英文。 - dan04
@Timwi,我原本以为中文和日文在UTF-8下只需要2个八位字节就可以了。感谢您的纠正。 - JSBձոգչ
1
没问题。如果它们只需要2个八位字节,那么这些字节必须是二进制形式的110xxxxx 10xxxxxx,但不能是1100000x 10xxxxxx,你只能有2^11−2^7 = 1920个字符。虽然平假名和片假名可能勉强可以放在里面(还有西里尔文、希腊文、亚美尼亚文、阿拉伯文、希伯来文等等),但汉字太多了,不可能放得下。 - Timwi

1

没有任何字符需要使用UTF-16而不是UTF-8。UTF-8和UTF-16(以及其他一些不推荐的格式)都可以编码整个UCS(这就是UTF的含义)。

有些流在UTF-16中比UTF-8小。然而,在实践中,这样的流主要包含语言上非常简洁的亚洲表意文字。但是,XML需要一些具有特定含义的0x20-0x7F范围内的字符,并且往往使用基于字母的脚本来表示元素和属性名称。

由于这些表意文字的简洁性,XML标记(包括元素和属性名称以及小于号和大于号)与面向人类的文本的比率将远高于使用字母和音节文字的语言。因此,即使在纯文本用UTF-16比相同文本用UTF-8更小的情况下,当涉及到XML时,这种差异也会更小,或者UTF-8仍然会更小。

通常情况下,使用UTF-8进行传输和存储。

编辑:刚注意到您还在压缩。在这种情况下,平衡更不重要,只需使用UTF-8即可。


然而,在实际应用中,此类数据流主要包含语言上非常简练的亚洲表意文字。这只适用于中文和日文,但不适用于朝鲜语、印度所有非拉丁文字、泰语、老挝语、藏语、乔治亚语等所有非拉丁文字的语言。 - Timwi
实际上,更准确地说,这适用于一些韩国人,而不是所有日本人(不知道中国人怎么样)。除非这种情况在数据源中占据主导地位(在这种情况下,我会建议始终使用UTF-16),否则我会坚持以上所述。 - Jon Hanna

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接