我是一名有用的助手,可以为您翻译文本。
(我正在回答您的问题“同一个字符可以有两个不同的UTF-8编码吗?”,这与帖子内部的问题有很大区别。)
(“字符”通常表示字符串元素。它含糊不清,在这里使用它并不正确。Unicode术语对于视觉表示即字形的术语是“grapheme”。)
是的,多个代码点序列可以导致相同的字形。例如,下面两个都是可能的:
U+00EB LATIN SMALL LETTER E WITH DIAERESIS
并且
U+0065 LATIN SMALL LETTER E
U+0308 COMBINING DIAERESIS
应该显示为“ë”。让我们看看您的浏览器如何处理:
- U+00EB: “ë”
- U+0065,0308: “ë”
在UTF-8中,这些码点将被编码为
- U+00EB: C3 AB
- U+0065: 65
- U+0308: CC 88
人们可以使用Unicode::Normalize的NFC
或NFD
将字符串规范化为两种格式之一(由您选择)。
$ 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”代表编码的代码点。必须使用最短的编码方式,因此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 的 Encode 模块将该序列视为无效,因此对于 Perl 来说,这不应该是一个问题。