Как мне "расшифровать" символ UTF-8?
Давайте предположим, что я хочу написать функцию для сравнения двух символов Юникода. Как мне это сделать? Я прочитал несколько статей вокруг (как это), но все еще не получил это. Давайте принимать €
в качестве ввода. Это в диапазоне 0x0800
а также 0xFFFF
поэтому он будет использовать 3 байта для его кодирования. Как мне это декодировать? побитовая операция, чтобы получить 3 байта из wchar_t
и хранить в 3 char
s? Код в примере на 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. Лучше не пытаться. Или:
Преобразуйте их оба в широкий формат (32-разрядное целое число) и сравните это арифметически. Увидеть
wstring_convert
или ваша любимая функция продавца; или жеПреобразуйте их в строки из 1 символа и используйте функцию, которая сравнивает строки в кодировке UTF-8. Не существует стандартного способа сделать это в C++, но это предпочтительный метод в других языках, таких как Ruby, PHP, что угодно.
Просто, чтобы прояснить ситуацию, трудно взять необработанные биты / байты / символы, закодированные как UTF_8, и сравнить их. Это потому, что ваше сравнение должно учитывать кодировку, чтобы знать, сравнивать ли 8 бит, 16 бит или больше. Если вы можете каким-то образом превратить необработанные биты данных в строку с нулевым символом в конце, тогда сравнение будет легко с использованием обычных строковых функций. Эта строка может иметь длину более одного байта / октета, но она будет представлять один символ / кодовую точку.
Windows - это особый случай. Широкие символы - короткие int (16 бит). Исторически это означало UCS-2, но оно было переопределено как UTF-16. Это означает, что все действительные символы в базовой многоязычной плоскости (BMP) можно сравнивать напрямую, поскольку они будут занимать одно короткое целое число, а другие - нет. Я не знаю ни одного простого способа иметь дело с 32-битными широкими символами (представленными как простое int) вне BMP в Windows.