C - Как конвертировать широкоугольные символы японского языка в UTF-8? - PullRequest
0 голосов
/ 05 октября 2019

Попытка преобразовать японские символы, хранящиеся в широком символе, в UTF-8, чтобы сохранить значение в файле json, используя библиотеку cJSON. Сначала попытался использовать wcstombs_s, но, видимо, это не поддерживает японские символы:

size_t len = wcslen(japanese[i].name) + 1;
char* japanese_char = malloc(len);
if (japanese_char == NULL) {
    exit(EXIT_FAILURE);
}
size_t sz;
wcstombs_s(&sz, japanese_char, len, japanese[i].name, _TRUNCATE);

Затем, основываясь на других ответах, но также и при успешном преобразовании из json UTF-8 в широкий символ, попробовал противоположную функцию какследует, но целевой буфер dest содержит только символы мусора:

size_t wcsChars = wcslen(japanese[i].name);
size_t sizeRequired = WideCharToMultiByte(CP_UTF8, 0, japanese[i].name, wcsChars, NULL, 0, NULL, NULL);
char* dest = calloc(sizeRequired, 1);
WideCharToMultiByte(CP_UTF8, 0, japanese[i].name, wcsChars, dest, sizeRequired, NULL, NULL);
free(dest);

Широкий символ (wchar_t), который я пытаюсь преобразовать, ササササササササササササササササ хранится в japanese[i].name (a wchar_t*в структуре). Цель состоит в том, чтобы использовать cJSON_CreateString в cJSON для сохранения значения в json-файле в кодировке UTF-8.

Вопрос: Как правильно преобразовать японский из wchar_t в символ UTF-8? в C (не C ++)?

1 Ответ

0 голосов
/ 05 октября 2019

Ваш код wcstombs_s() передает неверное значение параметру sizeInBytes:

sizeInBytes

Размер в байтах mbstr буфер.

Вы передаете в символ число japanese[i].name, а не выделенный байт число japanese_char. Они не имеют одинакового значения.

Кодовые точки Unicode кодируются в UTF-16 (какие строки wchar_t кодируются как в Windows), используя 2 или 4 байта каждая, и в UTF-8, используя 1-4 байтакаждый, в зависимости от их стоимости. Кодовые точки Unicode в диапазоне U+0080..U+FFFF занимают больше байтов в UTF-8, чем в UTF-16, поэтому возможно, что ваш буфер japanese_char должен быть фактически выделен больше, чем ваши japanese[i].name данные. Так же, как вы можете позвонить WideCharToMultiByte(), чтобы определить необходимый размер буфера назначения, вы можете сделать то же самое с wcstombs_s().

size_t len = 0;
wcstombs_s(&len, NULL, 0, japanese[i].name, _TRUNCATE);
if (len == 0)
    exit(EXIT_FAILURE);
char* japanese_char = malloc(len);
if (!japanese_char)
    exit(EXIT_FAILURE);
wcstombs_s(&len, japanese_char, len, japanese[i].name, _TRUNCATE);
...
free(japanese_char);

Ваш WideCharToMultiByte() код не имеет нулевого завершения dest из-за того, что вы передали явный размер параметру cchWideChar.

cchWideChar

Размер строки в символах, указанной в lpWideCharStr. В качестве альтернативы, этот параметр может быть установлен в -1, если строка заканчивается нулем. Если cchWideChar установлен в 0, функция завершается ошибкой.

Если этот параметр равен -1, функция обрабатывает всю входную строку, включая завершающий нулевой символ. Поэтому результирующая строка символов имеет завершающий нулевой символ, и длина, возвращаемая функцией, включает этот символ.

Если для этого параметра задано положительное целое число, функция обрабатывает точно указанное числоперсонажи. Если указанный размер не содержит завершающий нулевой символ, результирующая строка символов не заканчивается нулем, а возвращаемая длина не включает этот символ.

cJSON_CreateString() ожидает нулевое значениеchar* строкаПоэтому вам нужно либо:

  • добавить +1 к параметру num calloc(), чтобы учесть отсутствующий нулевой терминатор.
size_t wcsChars = wcslen(japanese[i].name);
size_t len = WideCharToMultiByte(CP_UTF8, 0, japanese[i].name, wcsChars, NULL, 0, NULL, NULL);
char* japanese_char = malloc(len + 1);
if (!japanese_char)
    exit(EXIT_FAILURE);
WideCharToMultiByte(CP_UTF8, 0, japanese[i].name, wcsChars, japanese_char, len, NULL, NULL);
japanese_char[len] = '\0';
...
free(japanese_char);
  • добавьте +1 к возвращаемому значению wcslen() или установите для параметра cchWideChar WideCharToMultiByte() значение -1, чтобы включить нулевой терминатор в вывод.
size_t wcsChars = wcslen(japanese[i].name) + 1;
size_t len = WideCharToMultiByte(CP_UTF8, 0, japanese[i].name, wcsChars, NULL, 0, NULL, NULL);
if (len == 0)
    exit(EXIT_FAILURE);
char* japanese_char = malloc(len);
if (!japanese_char)
    exit(EXIT_FAILURE);
WideCharToMultiByte(CP_UTF8, 0, japanese[i].name, wcsChars, japanese_char, len, NULL, NULL);
...
free(japanese_char);
size_t len = WideCharToMultiByte(CP_UTF8, 0, japanese[i].name, -1, NULL, 0, NULL, NULL);
if (len == 0)
    exit(EXIT_FAILURE);
char* japanese_char = malloc(len);
if (!japanese)
    exit(EXIT_FAILURE);
WideCharToMultiByte(CP_UTF8, 0, japanese[i].name, -1, japanese_char, len, NULL, NULL);
...
free(dest);
...