2016-07-20 3 views
3

У меня есть массив из uint32_t элементов, каждый из которых хранит код для не-латинского символа Юникода. Как распечатать их на консоли или сохранить в файле как кодированные символы UTF-8? Я понимаю, что они могут не отображаться должным образом на консоли, но они должны отображаться нормально, если я открою их в совместимом редакторе.Как печатать коды Unicode как символы в C?

Я пробовал использовать wprintf(L"%lc", UINT32_T_VARIABLE) и fwprintf(FILE_STREAM, L"%lc", UINT32_T_VARIABLE), но безрезультатно.

+0

Вы уверены, что 'stdout' не был байтовым? – EOF

+0

@EOF: фактически 'stdout' должен быть байтовым, и для этой работы должен быть выбран правильный язык. – chqrlie

+0

@chqrlie: Нет, если вы хотите использовать 'wprintf()', как это делает OP. – EOF

ответ

1

Вы должны сначала выбрать правильную локаль с:

#include <locale.h> 

setlocale(LC_ALL, "C.UTF-8"); 

или

setlocale(LC_ALL, "en_US.UTF-8"); 

, а затем использовать printf или fprintf с форматом %lc:

printf("%lc", UINT32_T_VARIABLE); 

Это будет работать только для кодовых точек Unicode достаточно мала, чтобы вписаться в a wchar_t. Для более полного и портативного решения вы можете использовать Unicode для преобразования UTF-8 самостоятельно, что не очень сложно.

+0

Настройка локали не помогает. 'fprintf()' и 'wprintf()' только печатать/хранить пустое пространство, а 'fwprintf()' хранит неправильные символы в файле. – hazrmard

+0

Какова ваша платформа и компилятор? – chqrlie

+0

Win10, gcc 5.3, Cygwin – hazrmard

0

Лучше всего использовать существующий код, если он доступен.

Роллинг собственный код Юникода на UTF8 - это просто, но все же легко повредить. Ответ исправлялся 2 раза. @Jonathan Leffler@chqrlie, поэтому строгое тестирование рекомендуется для любого самокодируемого решения. Следование - это слегка проверенный код для преобразования кодовой точки в массив.
Обратите внимание, что результатом является не строка .

// Populate utf8 with 0-4 bytes 
// Return length used in utf8[] 
// 0 implies bad codepoint 
unsigned Unicode_CodepointToUTF8(uint8_t *utf8, uint32_t codepoint) { 
    if (codepoint <= 0x7F) { 
    utf8[0] = codepoint; 
    return 1; 
    } 
    if (codepoint <= 0x7FF) { 
    utf8[0] = 0xC0 | (codepoint >> 6); 
    utf8[1] = 0x80 | (codepoint & 0x3F); 
    return 2; 
    } 
    if (codepoint <= 0xFFFF) { 
    // detect surrogates 
    if (codepoint >= 0xD800 && codepoint <= 0xDFFF) return 0; 
    utf8[0] = 0xE0 | (codepoint >> 12); 
    utf8[1] = 0x80 | ((codepoint >> 6) & 0x3F); 
    utf8[2] = 0x80 | (codepoint & 0x3F); 
    return 3; 
    } 
    if (codepoint <= 0x10FFFF) { 
    utf8[0] = 0xF0 | (codepoint >> 18); 
    utf8[1] = 0x80 | ((codepoint >> 12) & 0x3F); 
    utf8[2] = 0x80 | ((codepoint >> 6) & 0x3F); 
    utf8[3] = 0x80 | (codepoint & 0x3F); 
    return 4; 
    } 
    return 0; 
} 

// Sample usage 
uint32_t cp = foo(); 
uint8_t utf8[4]; 
unsigned len = Unicode_CodepointToUTF8(utf8, cp); 
if (len == 0) Handle_BadCodePoint(); 
size_t y = fwrite(utf8, 1, len, stream_opened_in_binary_mode); 
+1

Правильный диапазон для высоких и низких суррогатов - U + D800 .. U + DFFF (разделение на высокие суррогаты U + D800 .. U + DBFF и низкие суррогаты U + DC00 .. U + DFFF), а не U + D000. U + DFFF как в одной версии кода в ответе. Диаграмма для [U + AC00 .. U + D7AF] (http://www.unicode.org/charts/PDF/UAC00.pdf) охватывает хангульские слоги. Как вы сказали, легко его испортить. –

+0

@Jonathan Leffler Право вы - код исправлен – chux

+1

Код неверен для байтов промежуточной последовательности в 3-х и 4-байтовых случаях: вы должны маскировать бит '0x40' после смещения' codepoint' ... * простой, но простой на самом деле испортить. – chqrlie

Смежные вопросы