Как мне "расшифровать" символ UTF-8?

Давайте предположим, что я хочу написать функцию для сравнения двух символов Юникода. Как мне это сделать? Я прочитал несколько статей вокруг (как это), но все еще не получил это. Давайте принимать в качестве ввода. Это в диапазоне 0x0800 а также 0xFFFF поэтому он будет использовать 3 байта для его кодирования. Как мне это декодировать? побитовая операция, чтобы получить 3 байта из wchar_t и хранить в 3 chars? Код в примере на C может быть отличным.

Вот мой C-код для "декодирования", но, очевидно, показывает неправильное значение для декодирования Unicode...

#include <stdio.h>
#include <wchar.h>

void printbin(unsigned n);
int length(wchar_t c);
void print(struct Bytes *b);

// support for UTF8 which encodes up to 4 bytes only
struct Bytes
{
    char v1;
    char v2;
    char v3;
    char v4;
};

int main(void)
{
    struct Bytes bytes = { 0 };
    wchar_t c = '€';
    int len = length(c);

    //c = 11100010 10000010 10101100
    bytes.v1 = (c >> 24) << 4; // get first byte and remove leading "1110"
    bytes.v2 = (c >> 16) << 5; // skip over first byte and get 000010 from 10000010
    bytes.v3 = (c >> 8)  << 5; // skip over first two bytes and 10101100 from 10000010
    print(&bytes);

    return 0;
}

void print(struct Bytes *b)
{
    int v1 = (int) (b->v1);
    int v2 = (int)(b->v2);
    int v3 = (int)(b->v3);
    int v4 = (int)(b->v4);

    printf("v1 = %d\n", v1);
    printf("v2 = %d\n", v2);
    printf("v3 = %d\n", v3);
    printf("v4 = %d\n", v4);
}

int length(wchar_t c)
{
    if (c >= 0 && c < 0x007F)
        return 1;
    if (c >= 0x0080 && c <= 0x07FF)
        return 2;
    if (c >= 0x0800 && c <= 0xFFFF)
        return 3;
    if (c >= 0x10000 && c <= 0x1FFFFF)
        return 4;
    if (c >= 0x200000 && c <= 0x3FFFFFF)
        return 5;
    if (c >= 0x4000000 && c <= 0x7FFFFFFF)
        return 6;

    return -1;
}

void printbin(unsigned n)
{
    if (!n)
        return;

    printbin(n >> 1);
    printf("%c", (n & 1) ? '1' : '0');
}

1 ответ

Нелегко сравнивать символы в кодировке UTF-8. Лучше не пытаться. Или:

  1. Преобразуйте их оба в широкий формат (32-разрядное целое число) и сравните это арифметически. Увидеть wstring_convert или ваша любимая функция продавца; или же

  2. Преобразуйте их в строки из 1 символа и используйте функцию, которая сравнивает строки в кодировке UTF-8. Не существует стандартного способа сделать это в C++, но это предпочтительный метод в других языках, таких как Ruby, PHP, что угодно.


Просто, чтобы прояснить ситуацию, трудно взять необработанные биты / байты / символы, закодированные как UTF_8, и сравнить их. Это потому, что ваше сравнение должно учитывать кодировку, чтобы знать, сравнивать ли 8 бит, 16 бит или больше. Если вы можете каким-то образом превратить необработанные биты данных в строку с нулевым символом в конце, тогда сравнение будет легко с использованием обычных строковых функций. Эта строка может иметь длину более одного байта / октета, но она будет представлять один символ / кодовую точку.


Windows - это особый случай. Широкие символы - короткие int (16 бит). Исторически это означало UCS-2, но оно было переопределено как UTF-16. Это означает, что все действительные символы в базовой многоязычной плоскости (BMP) можно сравнивать напрямую, поскольку они будут занимать одно короткое целое число, а другие - нет. Я не знаю ни одного простого способа иметь дело с 32-битными широкими символами (представленными как простое int) вне BMP в Windows.

Другие вопросы по тегам