Как мне прочитать строки Unicode-16 из файла, используя методы POSIX в Linux? - PullRequest
5 голосов
/ 05 февраля 2009

У меня есть файл, содержащий строки 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 ]

6 голосов
/ 05 февраля 2009

Самый простой способ - конвертировать файл из 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.

4 голосов
/ 05 февраля 2009

(всегда ли 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 в качестве кодировки по умолчанию для локали, благодаря всем \ 0.

2 голосов
/ 09 февраля 2009

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

1 голос
/ 05 февраля 2009

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

...