是否应该弃用除UTF-8(也许还有UTF-16 / UTF-32)之外的字符编码?


31

我的烦恼正在研究如此众多的软件项目,这些项目具有大量的字符集支持代码。不要误会我的意思,我全都出于兼容性的考虑,并且我很高兴文本编辑器允许您打开并保存多个字符集的文件。令我烦恼的是,如何将非通用字符编码的泛滥称为“适当的Unicode支持”而不是“问题”。

例如,让我选择PostgreSQL及其字符集支持。PostgreSQL处理两种类型的编码:

  • 客户端编码:用于客户端和服务器之间的通信。
  • 服务器编码:用于将文本内部存储在数据库中。

我可以理解为什么支持很多客户端编码是一件好事。它使不在UTF-8中运行的客户端无需进行转换即可与PostgreSQL通信。我不明白的是:为什么PostgreSQL支持多种服务器编码?数据库文件(几乎总是)从一个PostgreSQL版本到另一个版本不兼容,因此,跨版本兼容性不是这里的问题。

UTF-8是唯一可以对所有Unicode代码点进行编码的标准,兼容ASCII的字符集(如果我记错了,请告诉我)。我在阵营中认为UTF-8是最好的字符集,但我愿意忍受其他通用字符集,例如UTF-16和UTF-32。

我认为所有不通用的字符集都应弃用。他们不应该有任何令人信服的理由吗?


4
@mario:UTF-8的原始定义最多允许6个字节。后来被人为限制为仅覆盖UTF-16可以支持的字符。
dan04 2011年

6
至少PostgreSQL 故意处理多种字符编码。不得不处理UTF-8和Windows-1252的随机混合很糟糕,因为有人根本不在乎。
dan04 2011年

5
@ dan04:使用俄语文本曾经是一个痛苦,因为它们使用了多种编码,这些编码本质上是不同的,并且通常只是通过使用不同的字体来破解某些东西才能正常工作(这通常取决于元数据中使用的编码)。总而言之,一团糟。我怀疑他们已经清理了(可能是改用UTF-8),因为来自该方向的支持请求数量已经下降。
Donal Fellows

3
理论上的Unicode范围是从0到0x10ffff。而已。这就是Unicode标准所说的。UTF-8会处理所有Unicode,并且会一直处理。它没有涵盖非Unicode的假设范围,但涵盖了所有Unicode。
gnasher729,2015年

Answers:


16

自从您提到PostgreSQL以来,我可以授权地说,如此详细地支持非UTF8服务器端编码的主要杀手原因是日语需要它。显然,在Unicode与各种日语“旧式”编码之间始终不可能进行相同的往返转换,并且在某些情况下,不同供应商之间的转换表甚至有所不同。确实令人困惑,但显然如此。(广泛的字符集支持也是PostgreSQL在日本如此流行的原因之一。)

由于我们在谈论数据库系统,因此主要工作之一就是能够可靠地存储和检索用户定义的数据,因此有损字符集转换有时不会实现。例如,如果您使用的是Web浏览器,那么真正重要的是结果是否看起来不错,那么您可能可以摆脱支持较少的编码的麻烦,但是在数据库系统中,您有额外的要求。

其他答案中提到的其他一些原因也可作为支持性论据。但是,只要日本人否决,就不能减少对字符设置的支持。


因此,由于采用了这些编码,因此将文本转换为UTF-8以及将其转换回通常有损吗?即使转换立即完成(而不是从现在开始的6个月)?
乔伊·亚当斯

乔伊·亚当斯:显然是这样。
Peter Eisentraut 2011年

3
谷歌寻找“汉统一”的原因
彼得·维克托林

7

两个明显的原因:根据您存储的数据,转换为其他格式可能会花费大量时间和额外空间。如果您要存储400兆字节的信息,那么将存储需求增加一倍就没什么大不了了-但是,如果您要存储400 TB的信息,则意味着更多。将400 TB的数据从Shift-JIS转换为UTF-x也可能需要一些时间。

如果您拥有(例如)正常运行时间保证该数据库将在除特定年份以外的所有时间(例如每年10分钟)内可用并且您的数据库正在每秒更新数百次的情况下,这将变得特别困难。提醒您,在这种情况下仍然可以管理重大转化,但这并不是一件容易的事。在某些情况下,准备好进行此类转换可能需要花费数的计划。

如果您从(例如)仅支持ASCII的数据库开始,可能有充分的理由来讨论增加对所有这些编码的支持是否有意义-但是,如果您已经支持它们,那么从删除中获得的好处就很少支持他们。

特别要注意的是,通过简化代码或类似的方式,您可能几乎一无所获。无论如何,他们仍然需要所有转换例程来处理客户端和服务器之间的转换。这样,放弃支持将意味着放弃“写入磁盘”和“从磁盘读取”路径中的一个(次要)函数调用,但是减少(如果有的话)。如果您甚至在磁盘上支持两种编码,您甚至都不会获得-您仍然可以在其中调用函数,因此您真正要做的就是限制该函数支持的编码范围。

至少如果我要进行此设计,我可能会编写数据库的核心以在UCS-4中工作,然后在核心与磁盘之间以及核心与用户之间建立转换例程。在这两种情况下,我都将使用相同的例程集,因此最简单的方法是允许磁盘存储使用与允许客户端使用的完全相同的编码集。


1
Shift-JIS是非自同步的,这使搜索变得麻烦。不支持它,您获得极大的简化。
2011年

@ dan04:如果您已经有经过时间验证的Shift-JIS搜索/索引例程,则切换到UTF-8甚至UCS2可能会显着提高性能。对于数据库,您可以选择更好,更方便且常规的编码,例如UCS2或UTF-16。
9000

@ dan04:如果您可以完全不支持它,那么您将获得很多收益。只要您支持它来/去给客户,您就将被其大多数丑陋所困扰...
Jerry Coffin

5

仅将UTF-8存储在服务器上有两个问题:

  1. VARCHAR(20)列的限制是什么?那是20个字节还是20个“字符”(在Unicode中,当您考虑将字符,连字等组合在一起时,什么是“字符”?)。更糟糕的是CHAR(20),它实际上在哪里必须保留所有可能的空间:我相信在MySQL中,它只保留4倍于UTF-8编码列的字节数(因此为80字节CHAR(20)),以应付最坏的情况。
  2. 您需要在服务器编码和客户端编码之间执行恒定的编码转换。您可能会争辩说,您也想停止支持多种客户端编码,但是除非您这样做,否则所有字符串都需要一直进行转换。如果可以匹配服务器编码和客户端编码,则不需要进行转换。
  3. 正如其他人指出的那样,UTF-8在存储英语文本方面非常有效,但是对于其他语言(尤其是东亚语言)而言效率非常。我想,您可以允许将UTF-16或UTF-8用作西装。或压缩文本,但这会使索引和搜索效率低下。

说了这么多,我同意你的看法:传统编码几乎没有意义,而Unicode通常是所有新应用程序使用的最佳编码。如果今天我是从头开始编写数据库服务器,那么我将仅支持Unicode,而根本不支持任何旧式编码。

不同之处在于,今天使用的PostgreSQL和大多数其他数据库服务器出现 Unicode成为可行的选择之前。因此,他们已经支持旧式编码(当然,那时它们还不是旧式的),并且出于很大程度上出于意识形态的原因,将所有这些代码剔除没有什么意义。


10
“但是对于其他语言(特别是东亚语言)而言,效率很低” 即使在实践中?考虑一下这个中文维基百科页面。尽管它显示了很多中文字符,但在页面源中,ASCII字符几乎以7:1压倒了它们。
乔伊·亚当斯

2
如果您的CHAR(N)列中的N是明确定义的标识符格式的一部分(例如,VIN被定义为恰好是17个字符),那么它可能不需要组合字符或连字。如果不是,则N只是一个任意限制,应该宽泛地解释它以避免截断数据。
2011年

5
@Joey Adams:在HTML和XML上确实如此,其中标记本身占文本的很大一部分(这就是为什么我认为UTF-8是Web的不错选择)的原因,但是在数据库中您并不经常存储HTML。归根结底,这只是两个(或更少)差异的一个因素,实际上并没有那么多。
迪恩·哈丁

5
此答案中的项目符号第2点无关紧要:无论是否使用Unicode,它都适用。项目符号3绝对夸大了无效性及其范围。同时,此答案大大低估了由传统编码引起的问题。如果您一生中仅使用英语,就很容易假设问题不是什么大问题。
Timwi'1

2
@Dean:我不知道在不发布自己的答案的情况下不允许对答案发表评论。
Timwi'1

3

非通用(特别是单字节)编码确实有其位置:在以下系统上:

  • 没有足够的内存来存储Unicode字符数据库。
  • 在ROM中具有硬编码的单字节字体。
  • 无法访问Internet以提供不同编码文件的来源。

对于某些类型的嵌入式设备而言,今天确实如此。但在桌面上,并在服务器机房,非Unicode编码应该是长期的,现在已经过时。


3
我曾经有那样的家用电脑。在80年代初期,我摆脱了其中的大多数。
David Thornley

2

UTF-8最适合您1以英语为中心的英语使用者。如果您是日语用户,则大约99%的字符将占用3-4个字节,而不是UTF-16中的两个字节。

非拉丁方言在大小方面确实遭受UTF-8的困扰。别忘了,几年之内,您的大多数客户可能是中文,而且中文写作有数百万个字符。您无法使用UTF-8有效地维持这种状态。

否则,当我的文本文档不是UTF- something时,我会讨厌它。如果我需要适当的编码,我经常会不知所措。在我的书中,非Unicode编码已失效。

1.不要以自我为中心。我想做一个彩色的插图,但我不是真的。


3
@Matthew-4x显然比x大4倍(对于正x)。我看不到渐近符号在这里有多重要。我从未见过标榜渐进增长率的硬盘。通常,大小在驱动器的整个使用寿命中保持不变。
Steve314 2011年

3
无论如何,数百万个字符不适合Unicode。根据维基百科的文章,目前大约有六万个汉字。由于Unicode不仅是中文,这意味着相当多的中文字符在UTF-16中将占用四个字节,这与如今的UTF-8一样长。看到有关UTF-8和UTF-16的中文文本长度的统计数据将很有趣。
David Thornley

6
@David:> 99%的日语和汉语写作使用的字符在UTF-16中只需要2个字节,在UTF-8中只需要3个字节。需要更多字符的字符非常罕见和/或具有历史意义。
Timwi'1

8
请记住,日语和中文通常每个单词使用较少的字符。我使用的应用程序具有英文,日文和中文的大语言文件,并且全部以utf-8编码。中文文件实际上是最小的文件,而日语文件则比英文文件大15%。
砸了机器人的

3
废话。在UTF-16中占用两个字节的任何内容在UTF-8中占用不超过3个字节。在UTF-8中为四个字节的任何内容在UTF-16中为4个字节。没有“百万”个汉字,而且显然它们不适合16位。
gnasher729,2015年

1

Unicode从根本上被破坏了,不太可能被修复。它需要被更好的东西,真正的通用东西所代替。如果需要淘汰,则为Unicode。

Unicide的示例问题:

  • UTF8是一个合理的技巧,但是大多数基于UTF16的软件都已损坏。大多数支持Unicode的Windows应用程序都使用UTF16,包括操作系统本身。最常见的问题是不支持基本平面,即多字字符。

  • 汉族统一是一场无法缓解的灾难。如果没有额外的元数据,就不可能在单个文档中混合日文/中文/韩文文本,并且很难检测出应该使用哪种字体。

  • 组合字符是另一场灾难。更明智的编码方案将一个字符映射到一个代码,这使得处理字符串相对理智。Unicode没有。Unicode甚至不是一致的-汉字符主要是组合,但没有像欧洲组合字符那样编码。

  • 有些人的名字不能用Unicode正确书写,或者由于上述问题而极有可能不正确地显示。这可能会带来严重的后果,例如,当尝试登上与机票上(错误地)印有不正确护照的护照时。

由于这些问题以及更多问题,许多非英语软件无法使用Unicode,而是依赖于本地字符编码。这在日语和中文软件中尤为常见。

理想情况下,不建议使用Unicode。TRON字符编码可以很好地替代Unicode,并且与不会更新的现有软件在很大程度上兼容。


您声称不可能混合使用不同的字符变体(日文/韩文/中文)似乎已经过时了15年,即2002年的Unicode 3.2标准。Unicode支持变体选择器,在han编码点之后明确指定哪种形式的编码点应该显示。同样,组合字符也被指定为带有基本字符(a°)和特殊字形(å)的“组合变音标记”,反之,转换它们的过程是“规范化”。因此,不,Unicode并没有从根本上被破坏。
Thorsten S.18年

您可以说明许多缺陷。有些语言使用组合字符,有些则不使用,而Unicode不能决定使用哪种字符。正如我所指出的那样,大多数声称支持Unicode的软件还是不理解这些问题,即使使用选择器也会显示错误。不应期望程序员是语言专家,这是Unicode的另一个基本缺陷。
用户

0

也许是为了写作,但不是为了阅读。

现有的很多内容都使用这些编码,而诸如base64之类的某些编码却一无所获,因为某些文本协议要求将这些编码作为嵌入二进制数据的方式。

真正的问题是自动检测编码会导致安全漏洞。我不介意看到一些像UTF-7这样晦涩的编码消失了。

自动检测还往往无法很好地处理通过天真地串联字节串而产生的内容。


7
Base64不是字符编码。
dan04 2011年

0

我可以同意,数据库和新应用程序的默认字符编码应为某种UTF变体。我个人会选择UTF-16,因为这似乎是在空间和复杂性上的合理权衡(比UTF-8还要多)。也就是说,某些字符编码在某些情况下仍然有意义。

  • 如果要存储/传输base64文本,则只需要ASCII,甚至可以摆脱诸如电子邮件之类的7位编码协议。UTF-8的额外开销是不必要的。
  • 在这些较旧的字符编码上构建了多个文件和现有数据,因此能够读取它们很重要。

请注意,有4种标准UTF标准化算法。如果您担心多码点字符,可以使用将它们折叠为等效的单码点字符的两种规范化算法之一。它们之间的区别与字符的逻辑等效性与物理等效性有关。


1
拒绝投票的人可以说为什么他们拒绝投票吗?
Berin Loritsch 2011年

3
我没有拒绝投票,但base64的全部目的是在文本通道下传输二进制数据。如果您可以选择在该频道上使用的编码,则完全不会使用文本编码。即使您的频道确实是纯ASCII码,基数64也仅使用7位中的6位-已经是相当大的开销了。
Steve314

我希望有人不只是阅读要点。这些是使用UTF的例外。而且您对base 64仅使用8个字节中的6个是不正确的。第一组ASCII“字符”是不可打印的控制字符,这迫使base64中的某些字符使用8个字节中的7个。它有意避免高位,因为并不能保证所有这些字符都存在于每个代码页中,而0-127之间的字符则存在。
Berin Loritsch 2011年

2
@Berin-(1)不,但没有要点,“我同意”的内容就不多了;(2)base 64有64个“数字”。64位数字是6位,因为2 ^ 6 == 64。在7位代码空间(或8位,如果必须,甚至8个字节)中表示的方式与实际存在的数据量是分开的。避免使用非打印字符等是造成开销的原因 -这并不意味着开销不存在。选择一个为二进制数据设计的通道,不存在开销。
Steve314 2011年

3
请记住,base64是发明来处理通过纯文本通道发送二进制数据的。众所周知,它效率低下(3:4扩展),但是在某些运输方式上遇到了技术限制。传统将是电子邮件和UseNet论坛,但更现代的应用程序将二进制数据嵌入XML。有时,适当的渠道不存在,并且您必须克服现有渠道的限制。
Berin Loritsch'2
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.