C ++ для чтения и записи файлов UTF-32 - PullRequest
0 голосов
/ 02 мая 2018

Я хочу написать приложение для изучения языка для себя, используя Visual Studio 2017, C ++ и WindowsAPI (ранее известный как Win32). Операционная система является последней инсайдерской сборкой Windows 10, и обратная совместимость не является проблемой. Поскольку я предполагаю, что английский язык является родным языком пользователя, а язык, которым я в данный момент интересуюсь, является другим европейским языком, ASCII может быть достаточно Но я хочу сделать это на будущее (больше экзотических языков), а также хочу попробовать UTF-32. Ранее я использовал как UTF-8, так и UTF-16, хотя у меня больше опыта с последующими.

Благодаря std::basic_string было легко понять, как получить строку UTF-32:

typedef std::basic_string<char32_t> stringUTF32

Поскольку я использую WinAPI для всего персонала графического интерфейса, мне нужно сделать какое-то преобразование между UTF-32 и UTF-16.

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

Итак, мой вопрос: как записывать / открывать файлы в UTF-32? Я бы предпочел, чтобы сторонние библиотеки не требовались, если они не являются частью Windows или обычно поставляются с этой ОС.

Ответы [ 2 ]

0 голосов
/ 03 мая 2018

Меня сейчас интересует другой европейский язык, [поэтому] может хватить ASCII

Нет. Даже на простом английском. Вы знаете, как Microsoft Word создает «фигурные кавычки»? Это не символы ASCII. Все эти буквы с акцентами и умлауты, например. Французский или английский не являются символами ASCII.

Я хочу это на будущее

UTF-8, UTF-16 и UTF-32 могут кодировать каждую кодовую точку Unicode. Они все на будущее. UTF-32 не имеет преимущества перед двумя другими.

Также для проверки на будущее: я уверен, что некоторые сценарии используют символы (технический термин - «кластеры графем»), состоящие из более чем одного кода. Появляется беглый поиск Игра с персонажами деванагари .

Недостатком UTF-32 является поддержка других инструментов. Блокнот не открывает ваши файлы. Вне сравнения не буду. Код Visual Studio… нет. Visual Studio это сделает, но не позволит вам создавать такие файлы.

И Win32 API: у него есть функция MultiByteToWideChar , которая может конвертировать UTF-8 в UTF-16 (который необходимо передать во все вызовы Win32), но он не принимает UTF-32 .

Итак, мой честный ответ на этот вопрос: не . В противном случае следуйте ответу Никол.

0 голосов
/ 02 мая 2018

Если у вас есть последовательность char32_t, вы можете записать ее в файл, используя std::basic_ofstream<char32_t> (который я буду называть u32_ofstream, но этот typedef не существует). Это работает точно так же, как std::ofstream, за исключением того, что пишет char32_t с вместо char с. Но есть ограничения.

Большинство стандартных типов библиотек с перегрузкой operator<< настроены на тип символа. Так что они будут работать с u32_ofstream просто отлично. Проблема, с которой вы столкнетесь, относится к типам user . Они почти всегда предполагают, что вы пишете char, и поэтому определяются как ostream &operator<<(ostream &os, ...);. Такой вывод потока не может работать с u32_ofstream без слоя преобразования.

Но большая проблема, с которой вы столкнетесь, - это порядковые номера. u32_ofstream напишет char32_t в качестве собственного порядкового номера вашей платформы. Если ваше приложение считывает их обратно через u32_ifstream, это нормально. Но если другие приложения читают их или если вашему приложению нужно прочитать что-то, написанное в UTF-32 кем-то другим, это становится проблемой.

Типичным решением является использование "метки порядка байтов" в качестве первого символа файла. Unicode даже имеет определенную кодовую точку, выделенную для этого: \U0000FEFF.

Вот как работает спецификация. При написании файла вы пишете спецификацию перед любыми другими кодовыми точками.

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

constexpr char32_t native_bom = U'\U0000FEFF';

u32_ifstream is(...);
char32_t bom;
is >> bom;
if(native_bom == bom)
{
  process_stream(is);
}
else
{
  basic_stringstream<char32_t> char_stream
  //Load the rest of `is` and endian-convert it into `char_stream`.
  process_stream(char_stream);
}
...