Как читать строки Unicode-16 из файла с использованием методов POSIX в Linux?

У меня есть файл, содержащий строки UNICODE-16, которые я хотел бы прочитать в программе Linux. Строки были написаны из внутреннего формата WCHAR Windows. (Всегда ли Windows использует UTF-16, например, в японских версиях)

Я считаю, что могу читать их с использованием сырых чтений и конвертирования с помощью wcstombs_l. Однако я не могу понять, какой язык использовать. Выполнение "locale -a" на моих современных машинах Ubuntu и Mac OS X дает нулевые локали с utf-16 в их именах.

Есть ли лучший способ?

Обновление: правильный ответ и другие ниже помогли указать мне на использование libiconv. Здесь функция, которую я использую для преобразования. В настоящее время я использую его внутри класса, который превращает преобразования в однострочный фрагмент кода.

// Function for converting wchar_t* to char*. (Really: UTF-16LE --> UTF-8)
// It will allocate the space needed for dest. The caller is
// responsible for freeing the memory.
static int iwcstombs_alloc(char **dest, const wchar_t *src)
{ iconv_t cd; const char from[] = "UTF-16LE"; const char to[] = "UTF-8"; cd = iconv_open(to, from); if (cd == (iconv_t)-1) { printf("iconv_open(\"%s\", \"%s\") failed: %s\n", to, from, strerror(errno)); return(-1); } // How much space do we need? // Guess that we need the same amount of space as used by src. // TODO: There should be a while loop around this whole process // that detects insufficient memory space and reallocates // more space. int len = sizeof(wchar_t) * (wcslen(src) + 1); //printf("len = %d\n", len); // Allocate space int destLen = len * sizeof(char); *dest = (char *)malloc(destLen); if (*dest == NULL) { iconv_close(cd); return -1; } // Convert size_t inBufBytesLeft = len; char *inBuf = (char *)src; size_t outBufBytesLeft = destLen; char *outBuf = (char *)*dest; int rc = iconv(cd, &inBuf, &inBufBytesLeft, &outBuf, &outBufBytesLeft); if (rc == -1) { printf("iconv() failed: %s\n", strerror(errno)); iconv_close(cd); free(*dest); *dest = NULL; return -1; } iconv_close(cd); return 0;
} // iwcstombs_alloc()
4 ответа

(Всегда ли Windows использует UTF-16, например, в японских версиях)

Да, NT WCHAR всегда UTF-16LE.

("Системная кодовая страница, которая для японской установки действительно является cp932/Shift-JIS, все еще существует в NT в интересах многих, многих приложений, которые не являются Unicode-родными, FAT32-маршрутами и т.д.).

Однако wchar_t не гарантированно будет 16 бит, а в Linux его не будет, используется UTF-32 (UCS-4). Так что wcstombs_l вряд ли будет счастлив.

Правильная вещь - использовать библиотеку, например iconv, для ее чтения в любом формате, который вы используете внутри - предположительно wchar_t. Вы можете попытаться взломать его сами, забив байты, но вы, вероятно, получите такие вещи, как суррогаты.

Выполнение "locale -a" на моих современных машинах Ubuntu и Mac OS X дает нулевые локали с utf-16 в их именах.

Действительно, Linux не может использовать UTF-16 в качестве кодировки по умолчанию для локали благодаря всем\0s.


Самый простой способ - преобразовать файл из utf16 в исходную UNIX-кодировку utf8, а затем прочитать его,

iconv -f utf16 -t utf8 file_in.txt -o file_out.txt

Вы также можете использовать iconv (3) (см. man 3 iconv) для преобразования строки с использованием C. Большинство других языков имеет привязки к iconv.

Чем вы можете использовать любой локаль UTF-8, например en_US.UTF-8, которые обычно являются стандартными по умолчанию на большинстве дистрибутивов Linux.


Вы можете читать как двоичные файлы, а затем сделать свое собственное быстрое преобразование:  http://unicode.org/faq/utf_bom.html#utf16-3 Но, вероятно, безопаснее использовать библиотеку (например, libiconv), которая правильно обрабатывает неверные последовательности.


Я бы настоятельно рекомендовал использовать кодировку Unicode в качестве внутреннего представления вашей программы. Используйте UTF-16 или UTF-8. Если вы используете UTF-16 внутренне, то, очевидно, перевод не требуется. Если вы используете UTF-8, вы можете использовать локаль с .UTF-8 в нем, например, en_US.UTF-8.

licensed under cc by-sa 3.0 with attribution.