Как происходит конвертация UTF-16 и UTF-8? - PullRequest
1 голос
/ 02 октября 2019

Меня немного смущает преобразование кодовых точек 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", и вместо этого мыget "3624000652".

Как на самом деле происходит преобразование ??

Как для UTF-8 ,, 4-байтовое кодирование выглядит так11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

Но как это происходит в UTF-16 ?? Если кто-нибудь сможет объяснить мне это как можно проще, тогда это будет огромной помощью, потому что я искал это как последние несколько дней и не смог найти хорошего ответа, который имеет смысл для меня.

Сайтами, которые я использовал для конвертации, были Branah.com и rapidtables.com

1 Ответ

1 голос
/ 03 октября 2019

как мы получили это значение

как мы можем преобразовать его обратно в реальную кодовую точку

о суррогатных парах, как они работают?

Изучите алгоритм для кодирования в 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
...