【问题标题】:How UTF-16 and UTF-8 conversion happen?UTF-16 和 UTF-8 转换是如何发生的?
【发布时间】:2020-02-01 02:30:59
【问题描述】:

我对将 unicode 字符代码点转换为 UTF-16 有点困惑,我正在寻找能以最简单的方式向我解释的人。

对于像“????”这样的字符我们得到;

d801dc8c -->  UTF-16
0001048c -->  UTF-32
f090928c -->  UTF-8
66700    -->  Decimal Value

所以,UTF-16 十六进制值转换为“11011000 00000001 11011100 10001100”,即十进制值“3624000652”,所以我的问题是我们如何得到这个十六进制值?以及我们如何将其转换回“66700”的真实代码点。 ???

UTF-32 十六进制值转换为“00000000 0000001 00000100 10001100”,即十进制为“66700”,但 UTF-16 值不会转换回“66700”,而是得到“3624000652” .

转换实际上是如何发生的??

对于 UTF-8,4 字节编码 类似于 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

但这在 UTF-16 中是如何发生的?如果有人能以最简单的方式向我解释,那将是一个巨大的帮助,因为过去几天我一直在寻找它,但一直找不到对我有意义的好答案。

我用于转换的网站是Branah.comrapidtables.com

【问题讨论】:

  • UTF-16 使用 surrogate pairs 表示平面 0 以外的字符。
  • ???? (U+1048C) 在 UTF-8 中是十六进制 0xF0 0x90 0x92 0x8C,在 UTF-16 中是十六进制 0xDB01 0xDC8C,在 UTF-32 中是十六进制 0x0001048C。如果你用 codeunits 而不是 raw bytes 来表达它们会更容易阅读。 UTF-8 以 1-4 个 8 位代码单元对代码点进行编码。 UTF-16 以 1-2 个 16 位代码单元对代码点进行编码。 UTF-32 以 1 个 32 位代码单元对代码点进行编码。另请记住,UTF-16 和 UTF-32 代码单元受 endian 的约束,而 UTF-8 代码单元则不受。
  • @georg 我想了解更多关于代理对的信息,它们是如何工作的??
  • 考虑在http://unicode.org/faq 进行研究。我可以说,作为一个说英语的人,“代理人”似乎很奇怪。我会使用不同的行话:“alibi”。我的意思是保留某些代码点,因此它们不会与需要代码单元对的具有相同数值的 UTF-16 代码单元混淆。从 UTF-16 的角度来看,没有理由将这些值称为“代理”(或“不在场证明”)。从 Unicode 代码点的角度来看,这些值是“不在场证明”,因为它们引用了别处的东西。

标签: unicode encoding utf-8 utf-16


【解决方案1】:

我们如何得到这个值

我们如何将它转换回真正的代码点

关于代理对,它们是如何工作的?

学习algorithm for encoding to UTF-16

my $U = 66_700; # code point
if ($U > 0xffff) {
    my $U_prime = $U - 0x1_0000; # some intermediate value 0x0_0000 .. 0xF_FFFF
    sprintf '%d', $U_prime;      # 1164
    sprintf '0x%04X', $U_prime;  # 0x048C
    sprintf '0b%020b', $U_prime; # 0b00000000010010001100

    my $high_ten_bits = $U_prime << 10;  # range 0x000 .. 0x3FF
    sprintf '0b%010b', $high_ten_bits;   # 0b0000000001

    my $low_ten_bits = $U_prime ^ 2**10; # range 0x000 .. 0x3FF
    sprintf '0b%010b', $low_ten_bits;    # 0b0010001100

    my $W1 = $high_ten_bits + 0xD800; # high surrogate
    sprintf '%d', $W1;      # 55297
    sprintf '0x%04X', $W1;  # 0xD801
    sprintf '0b%016b', $W1; # 0b1101100000000001

    my $W2 = $low_ten_bits + 0xDC00;  # low surrogate
    sprintf '%d', $W2;      # 56460
    sprintf '0x%04X', $W2;  # 0xDC8C
    sprintf '0b%016b', $W2; # 0b1101110010001100

    # finally emit the concatenation of W1 and W2

    # your original arithmetic checks out:
    ($W1 << 16) + $W2   # 3624000652
}

反方向:

my @octets = (0xD8, 0x01, 0xDC, 0x8C);
my $W1 = ($octets[0] << 8) + $octets[1];
sprintf '%d', $W1;      # 55297
sprintf '0x%04X', $W1;  # 0xD801
sprintf '0b%016b', $W1; # 0b1101100000000001

my $W2 = ($octets[2] << 8) + $octets[3];
sprintf '%d', $W2;      # 56460
sprintf '0x%04X', $W2;  # 0xDC8C
sprintf '0b%016b', $W2; # 0b1101110010001100

my $high_ten_bits = $W1 - 0xD800;
sprintf '0b%010b', $high_ten_bits; # 0b0000000001

my $low_ten_bits = $W2 - 0xDC00;
sprintf '0b%010b', $low_ten_bits;  # 0b0010001100

my $U_prime = ($high_ten_bits << 10) + $low_ten_bits;
sprintf '%d', $U_prime;      # 1164
sprintf '0x%04X', $U_prime;  # 0x048C
sprintf '0b%020b', $U_prime; # 0b00000000010010001100

my $U = $U_prime + 0x1_0000;
sprintf '%d', $U; # 66700

【讨论】:

  • 对于正在学习 Unicode 转换的初学者来说,这非常令人困惑,而且太复杂而难以理解。那么,你能用简单的方式解释一下吗?有点像这个问题的答案 - stackoverflow.com/questions/58207814/…
  • 哪一部分令人困惑?你必须告诉我,这样我才能改进我的答案。 – 您可以自己在调试器中运行代码,也可以使用电子计算器手动执行每个步骤。
  • 您好,感谢您抽出宝贵时间提供帮助,非常感谢。在涉足了一段时间之后,我终于自己弄清楚了,但感谢您的时间,尽管这意味着很多。 (祝你有美好的一天)?
猜你喜欢
  • 1970-01-01
  • 2020-01-28
  • 2021-01-30
  • 2015-09-21
  • 2015-09-19
  • 2017-09-24
  • 1970-01-01
  • 2019-05-15
相关资源
最近更新 更多