Как моя программа может переключаться с ASCII на Unicode? - PullRequest
7 голосов
/ 01 сентября 2010

Я хочу написать программу на C ++, которая должна работать на Unix и Windows.Эта программа должна быть в состоянии использовать как: Unicode, так и не Unicode среды.Его поведение должно зависеть только от настроек среды.

Одна из приятных функций, которую я хочу иметь, - это манипулирование именами файлов, читаемыми из каталогов.Это может быть Unicode ... или нет.

Какой самый простой способ добиться этого?

Ответы [ 6 ]

9 голосов
/ 01 сентября 2010

Я хочу написать программу на C ++, которая должна работать в Unix и Windows.

Сначала убедитесь, что вы понимаете разницу между тем, как Unix поддерживает Unicode и как Windows поддерживает Unicode.

В дни до Юникода обе платформы были похожи в том, что в каждой локали были свои предпочтительные кодировки символов.Строки были массивами char.Один char = один символ, за исключением нескольких восточноазиатских локалей, которые использовали двухбайтовые кодировки (с которыми было неудобно работать из-за несамосинхронизации).

Но они подошли к Unicode в двух разныхспособы.

Windows NT приняла Unicode в первые дни, когда Unicode предназначался для 16-битной кодировки символов фиксированной ширины.Microsoft написала совершенно новую версию Windows API, используя 16-разрядные символы (wchar_t) вместо 8-разрядных символов.Для обратной совместимости они сохранили старый API "ANSI" и определили тонну макросов, чтобы вы могли вызывать либо версию "ANSI", либо "Unicode" в зависимости от того, был ли определен _UNICODE.

ВВ мире Unix (в частности, Plan 9 от Bell Labs) разработчики решили, что будет проще расширить существующую восточноазиатскую поддержку многобайтовых символов Unix для обработки 3-байтовых символов, и создали кодировку, теперь известную как UTF-8.В последние годы Unix-подобные системы делают UTF-8 кодировкой по умолчанию для большинства локалей.

Теоретически Windows может расширить поддержку ANSI для включения UTF-8, но у них все еще нет из-за жестко закодированных предположений о максимальном размере персонажа.Итак, в Windows вы застряли с API-интерфейсом ОС, который не поддерживает UTF-8, и библиотекой времени выполнения C ++, которая не поддерживает UTF-8.

В результате вы получите следующее:

  • UTF-8 - самая простая кодировка для работы в Unix.
  • UTF-16 - самая простая кодировка для работы в Windows.

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

Какой кодировкой это должно быть?

См. UTF-8 или UTF-16 илиUTF-32 или UCS-2

В итоге:

  • UTF-8 позволяет сохранить предположение о 8-битных единицах кода.
  • UTF-32 позволяет сохранить предположение о символах фиксированной ширины.
  • UTF-16 отстой , но все еще существует из-за Windows и Java.

wchar_t

- это стандартный тип широких символов C ++.Но его кодировка не стандартизирована: это UTF-16 в Windows и UTF-32 в Unix.За исключением тех платформ, которые используют зависящие от локали кодировки wchar_t в качестве наследства от восточноазиатских программ.

Если вы хотите использовать UTF-32, используйте uint32_t или эквивалентный typedefхранить символы.Или используйте wchar_t, если определено __STDC_ISO_10646__ и uint32_t.

Новый стандарт C ++ будет иметь char16_t и char32_t, что, надеюсь, прояснит путаницу в том, как представлять UTF-16.и UTF-32.

TCHAR

- это определение типа Windows для wchar_t (предполагается, что это UTF-16), когда определено _UNICODE и char (предполагается, что ANSI)") иначе.Он был разработан для работы с перегруженным Windows API, упомянутым выше.

В мое мнение , TCHAR отстой.Он сочетает в себе недостатки зависимости от платформы char с недостатками зависимости от платформы wchar_t.Избегайте этого.

Самое важное соображение

Кодировки символов касаются обмена информацией.Вот что означает «II» в ASCII.Ваша программа не существует в вакууме.Вы должны читать и записывать файлы, которые с большей вероятностью будут закодированы в UTF-8, чем в UTF-16.

С другой стороны, вы можете работать с библиотеками, которые используют UTF-16 (или болеередко, UTF-32) персонажи.Это особенно верно для Windows.

Я рекомендую использовать форму кодирования, которая минимизирует количество конверсий, которое вам нужно сделать.

Эта программа должна быть в состоянии использовать оба: Unicode и не Unicode окружающая среда

Было бы намного лучше, если бы ваша программа работала полностью в Юникоде внутри и имела бы дело только с унаследованными кодировками для чтения устаревших данных (или записи их, но только , если явно задан вопрос).

2 голосов
/ 01 сентября 2010

Вы должны решить, как вы будете представлять текст внутри.
Это должно быть постоянным, независимо от того, что еще вы выберете.

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

UTF-8 отлично подходит для хранения и передачи, так как хорошо сжимается.
Но мне не нравится как внутреннийпредставление, поскольку оно имеет переменную длину.

UTF-16: должен был быть спасителем всего человечества.
Но было быстро заменено UTF-32

UTF-32: исправлено с,Поэтому отлично подходит для внутреннего представления и манипулирования.
Простота преобразования в / из UTF-8.
Очень громоздкий (каждый символ занимает 4 байта).

Большинство ОС уже преобразовали в строку UTF.представление или движутся в этом направлении.Таким образом, использование внутреннего формата obld, такого как ISO-8859, просто означает, что вызовы ОС вызовут дополнительную работу, поскольку строка преобразуется в / из UTF.В результате это кажется пустой тратой времени (мне).

1 голос
/ 01 сентября 2010

Лично я бы пошел другим путем.

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

Определенная кодировка предназначена для простого взаимодействия, однако, поскольку Unix по умолчанию использует UTF-8, а Windows - UTF-16, невозможно иметьуниверсальное кодирование.Поэтому я бы просто предложил использовать ваше собственное внутреннее представление и применить подходящее преобразование в зависимости от целевой ОС.Это связано с общим интерфейсом к нужным вам функциям и реализацией для каждой ОС / кодировки.

Также обратите внимание, что вы сможете изменять кодировку / декодирование на лету независимо от используемой платформы (например, вам может быть предложено использовать UTF-32 в Unix для определенного файла), еще одна причина НЕ использовать данную кодировку.

Подводя итог:

  • ICU замечательно
  • , если вы реализуете его сами и хотите быть несколько «стандартным», используйте UTF-32 (4 байта на точку)
  • , если у вас недостаточно памяти, 21 бит (<3 байта) достаточно для кодирования всех существующих точек. </li>

Преобразование может показаться «ресурсоемким», но:

  • вы можете сделать это потоковым
  • это намного быстрее чем ввод / вывод

Мои 2 кт, как говорится:)

1 голос
/ 01 сентября 2010

Идентификатор локали "" (пустая строка) указывает локаль по умолчанию для конкретной реализации. Таким образом, если вы установите глобальную локаль на std::locale(""), то теоретически вы получите локаль по умолчанию, которая инициализируется на основе настроек локали среды. Это примерно столько же, сколько вам дает стандартный c ++.

Это имеет некоторые серьезные ограничения для Windows, где MSVC не предоставляет никаких std :: locale с кодировкой UTF-8. И Mac OS X не предоставляет никакой std :: locale, кроме культурно-нейтральной локали "C".

На практике принято стандартизировать std :: string в кодировке UTF-8 везде, где есть ваше приложение. Затем в тех конкретных случаях, когда вам нужно взаимодействовать с ОС, выполните преобразование кода по мере необходимости. Например, вы будете использовать const char *, закодированный с помощью UTF-8, для определения имени файла в Unix, но wchar *, закодированный с помощью UTF-16, для определения имени файла в windows.

UTF-8 - это широко рекомендуемый внутренний набор символов для приложений, предназначенных для переноса. UTF-16 имеет те же проблемы кодирования с переменной шириной, что и UTF-8, плюс использует больше места для множества языков. Также UTF-16 добавляет проблему с порядком байтов и имеет относительно небольшую поддержку в Unix. UTF-32 - самая простая кодировка для работы, но она также использует больше места и не имеет встроенной поддержки для Windows.

1 голос
/ 01 сентября 2010

Вы должны решить, какую кодировку Unicode вы хотите использовать, например, UTF-8, ISO-8859-1 и т. Д. Затем вы должны учитывать это в вашем C ++ во всех ваших манипуляциях со строками.Например, взгляните на w_char и wstring.В среде, не поддерживающей Юникод, я предполагаю, что вы имеете в виду, что входные переменные будут только в ascii?

0 голосов
/ 01 сентября 2010

Лучший способ, который я видел, это иметь typedef s и очень мало макросов, определенных на основе условной компиляции. Например:

#ifdef UNICODE
#define mychar wchar_t
#define s(a) L ## a
typedef std::wstring mystringa;
#else
#define mychar char
#define s(a) a
typedef std::string mystringa;
#endif
typedef std::basic_string<mychar> mystringb;

и так далее. Затем вы будете использовать строки как s("foo") и mystringa(s("foo"));. Я показал два способа создания строкового типа. Либо должно работать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...