能有2个不同的UTF-8编码为相同的字符?(Can there be 2 different UTF

2019-07-29 11:02发布

我正在写一个需要从UTF-8的转码输入到ISO-8859-1的应用程序(拉丁文1)。

所有工作正常,但我有时会收到一些元音字符编码奇怪。 例如,拉丁1 C 2点(将0xEB)通常是为UTF-8 0xC3是0xAB,但有时也如0xC3 0×83为0xC2是0xAB。

这件事发生了一些来自不同来源的时间,并指出,第一和最后一个字符匹配我的期望,莫不是一种编码规则,我的图书馆不知道?

Answer 1:

$ "\xC3\x83\xC2\xAB"
ë
$ use Encode

$ decode 'UTF-8', "\xC3\x83\xC2\xAB"
ë

你已经双UTF-8编码。 编码::修复是处理的一个方法。



Answer 2:

某些Unicode字符可以在一个组合分解的形式来表示。 例如,德国元音-U ü既可以由单个字符来表示ü或通过u接着¨ ,其中文本渲染器后合并。

参见维基百科文章的Unicode等价的血淋淋的细节。

因此,统一的库通常提供的方法或功能正常化的字符串为这种或那种形式,所以你可以对它们进行比较。



Answer 3:

(我回答您的问题的问题,“ 这是从门柱内侧问题显著不同。)

(“字符”通常是指串元素,它是在兽暧昧,这不是在这里使用正确的字。Unicode的期限为一个可视化表示,一字形,是“石墨烯”。)

是的,有超过的代码点序列可以产生相同的石墨烯。 例如,无论是

U+00EB  LATIN SMALL LETTER E WITH DIAERESIS

U+0065  LATIN SMALL LETTER E
U+0308  COMBINING DIAERESIS

应显示为“E”。 让我们看看你的浏览器如何做:

  • U + 00EB: “E”
  • U + 0065,0308: “E”

在UTF-8,这些码点将被编码为

  • U + 00EB:C3 AB
  • U + 0065:65
  • U + 0308:88 CC

人们会使用Unicode的正常化::的NFCNFD为字符串正常化的两种格式(你的选择)之一。

$ perl -MUnicode::Normalize -E'
   $x = "\x{00EB}";
   $y = "\x{0065}\x{0308}";

   say     $x  eq     $y  ?1:0;
   say NFC($x) eq NFC($y) ?1:0;
   say NFD($x) eq NFD($y) ?1:0;
'
0
1
1

还有一些所谓的UTF-8“超长”的编码。 (具体而言UTF-8,不是一般的UNICODE)在UTF-8,Unicode码点使用以下四种位模式之一编码:

1 0xxxxxxx
2 110xxxxx 10xxxxxx
3 1110xxxx 10xxxxxx 10xxxxxx
4 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

的“X” s为代码点进行编码。 我们必须用最短的,所以U + 00EB会

0000 0000 1110 1011
      --- ---- ----

   -----   ------
110xxxxx 10xxxxxx
11000011 10101011
C3       AB

但是,聪明的人会做

0000 0000 1110 1011
---- ---- ---- ----

    ----   ------   ------
1110xxxx 10xxxxxx 10xxxxxx
11100000 10000011 10101011
E0       83       AB

应用程序应该拒绝E0 83 AB(或至少将其转换为C3 AB),但有些不这样做,可能会导致安全问题。 Perl的编码模块,把该序列为无​​效,所以它不应该是Perl的一个问题。



文章来源: Can there be 2 different UTF-8 encodings for the same character?