Чтение и распечатка кодировок Unicode и UTF-8 в C - PullRequest
0 голосов
/ 06 ноября 2011

Я использую Windows XP.
Я хочу читать из файлов в кодировках ASCII, UTF-8 и Unicode и выводить строки на стандартный вывод.
Я пытался использовать функции из wchar.h как fgetwc () / fputwc () и fgetws () / fputws (), они работают в ASCII, но не когда файл находится в UTF-8 или Unicode.Не печатает символы, специфичные для языка, и когда файл находится в Юникоде, он не печатает ничего, кроме коробки и первой буквы.
Есть ли способ создать программу на чистом C, которая будет читать файлы, сравнивать строкии распечатать их правильно на стандартный вывод независимо от кодировки файлов, передаваемых в программу?

Ответы [ 3 ]

1 голос
/ 07 ноября 2011

Поскольку вы работаете в Windows, ключ заключается в том, что вы хотите записать свои строки, используя функцию WriteConsoleW, предварительно собрав последовательность символов UTF-16, которую вы хотите записать,(Вы, вероятно, должны писать только несколько килобайт символов за раз.) Конечно, используйте GetStdHandle для получения дескриптора консоли.

Труднее определить кодировку файла.К счастью, вам не нужно различать ASCII и UTF-8, поскольку последний является строгим надмножеством первого.Но для любой другой однобайтовой кодировки вам нужно угадать.Некоторые файлы UTF-8, скорее всего, в Windows, чем где-либо, имеют кодированный в UTF-8 знак порядка следования байтов в начале файла;Это неприятно, поскольку спецификации не должны использоваться с UTF-8, но сильный индикатор, если таковой имеется.(Обнаружение UTF-16 проще, поскольку у него должна быть метка порядка байтов, или вы можете догадаться по наличию NUL (0) байтов.)

0 голосов
/ 07 ноября 2011

Вот небольшой фрагмент кода, который я использовал для печати различных символов вне подмножества ASCII Unicode (содержит обходные пути для того, что кажется ошибкой в ​​реализации printf () компилятора Open Watcom:

// Compile with Open Watcom C/C++ 1.9: wcl386 cons-utf8.c

#include <windows.h>
#include <stdio.h>
#include <stddef.h>

// Workarounds for printf() not printing multi-byte (UTF-8) strings
// with Open Watcom C/C++ 1.7-1.9.
// 0 - no workaround for printf()
// 1 - setbuf(stdout, NULL) before printf()
// 2 - fflush(stdout) after printf()
// 3 - WriteConsole() instead of printf()
#define PRINT_WORKAROUND 03

int main(void)
{
  DWORD err, i, j;
  // Code point ranges of characters to print
  static const DWORD ranges[][2] =
  {
    { 0x0A0, 0x0FF }, // Latin chars with diacritic marks + some others
    { 0x391, 0x3CE }, // Greek chars
    { 0x410, 0x44F }  // Cyrillic chars
  };

#if PRINT_WORKAROUND == 1
  setbuf(stdout, NULL);
#endif

  if (!SetConsoleOutputCP(CP_UTF8))
  {
    err = GetLastError();
    printf("SetConsoleOutputCP(CP_UTF8) failed with error 0x%X\n", err);
    goto Exit;
  }

  printf("Workaround: %d\n", PRINT_WORKAROUND);

  for (j = 0; j < sizeof(ranges) / sizeof(ranges[0]); j++)
  {
    for (i = ranges[j][0]; i <= ranges[j][1]; i++)
    {
      char str[8];
      int sz;
      wchar_t wstr[2];
      wstr[0] = i;
      wstr[1] = 0;

      sz = WideCharToMultiByte(CP_UTF8,
                               0,
                               wstr,
                               -1,
                               str,
                               sizeof(str),
                               NULL,
                               NULL);
      if (sz <= 0)
      {
        err = GetLastError();
        printf("WideCharToMultiByte() failed with error 0x%X\n", err);
        goto Exit;
      }

#if PRINT_WORKAROUND < 3
      printf("%s", str);
#if PRINT_WORKAROUND == 2
      fflush(stdout);
#endif
#else
      WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),
                   str,
                   sz - 1,
                   &err,
                   NULL);
#endif
    }

    printf("\n");
  }
  printf("\n");

Exit:

  return 0;
}

Вывод:

C:\>cons-utf8.exe

Workaround: 3
 ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ
ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡ΢ΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώ
АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя

Я не нашел способа печатать кодовые точки UTF-16 непосредственно на консоли в Windows XP, которая бы работала так же, как указано выше.

0 голосов
/ 06 ноября 2011

Есть ли способ сделать программу на чистом C, которая будет читать файлы, сравнивать строки и правильно распечатывать их на stdout независимо от кодировки файлов, передаваемых в программу?

Нет, программа, очевидно, также указала кодировку файлов.Внутренне вы можете представлять данные файлов с многобайтовыми строками в UTF-8 или с широкими строками.

...