Строки и кодировка символов в С++
Я прочитал несколько сообщений о лучших практиках для строк и кодировки символов на С++, но я немного борюсь с поиском подхода общей цели, который кажется мне достаточно простым и правильным. Могу ли я запросить комментарии по следующим вопросам? Я склонен использовать UTF-8 и UTF-32 и определить что-то вроде:
typedef std::string string8;
typedef std::basic_string<uint32_t> string32;
Класс string8 будет использоваться для UTF-8, а отдельный тип - только напоминание о кодировании. Альтернативой было бы для string8 быть подклассом std::string и удалить методы, которые не совсем подходят для UTF-8.
Класс string32 будет использоваться для UTF-32, когда требуется фиксированный размер символа.
Функции CPP UTF-8, utf8:: utf8to32() и utf8:: utf32to8(), или даже более простые функции-обертки, будут использоваться для преобразования между ними.
Ответы
Ответ 1
Если вы планируете просто передавать строки и никогда не будете их проверять, вы можете использовать простой std::string
, хотя это работа с бедными людьми.
Проблема в том, что большинство фреймворков, даже стандартных, глупо (я думаю), применяли кодирование в памяти. Я говорю глупо, потому что кодирование должно иметь значение только на интерфейсе, и эти кодировки не приспособлены для манипуляции данными внутри памяти.
Кроме того, кодирование легко (это простая транспозиция CodePoint → байты и наоборот), в то время как основная трудность заключается в том, чтобы манипулировать данными.
С 8-битными или 16-битными значениями вы рискуете вырезать символ посередине, потому что ни std::string
, ни std::wstring
не знают, что такое символ Юникода. Хуже того, даже с 32-битным кодированием существует риск ветки символа от диакритических знаков, которые применяются к нему, что также глупо.
Поддержка Unicode в С++ поэтому чрезвычайно подпадает, что касается стандарта.
Если вы действительно хотите манипулировать строкой Unicode, вам нужен контейнер с поддержкой Unicode. Обычный способ - использовать библиотеку ICU
, хотя ее интерфейс действительно C-ish. Однако вы получите все необходимое для работы в Unicode с несколькими языками.
Ответ 2
Этот подход, описанный здесь, может оказаться полезным. Это старая, но полезная техника.
Ответ 3
Не указано, какое кодирование символов должно использоваться для строки, wstring и т.д. Общим способом является использование unicode в широких строках. Какие типы и кодировки должны использоваться, зависит от ваших требований.
Если вам нужно передать данные только от A до B, выберите std::string с кодировкой UTF-8 (не вводите новый тип, просто используйте std::string). Если вы должны работать со строками (extract, concat, sort,...), выберите std:: wstring и как кодировку UCS2/UTF-16 (только BMP) для Windows и UCS4/UTF-32 в Linux.
Преимуществом является фиксированный размер: каждый символ имеет размер 2 (или 4 для UCS4) байтов, а std::string, когда UTF-8 возвращает неверные результаты length().
Для преобразования вы можете проверить sizeof (std:: wstring:: value_type) == 2 или 4, чтобы выбрать UCS2 или UCS4. Я использую библиотеку ICU, но могут быть простые библиотеки обертки.
Получение из std::string не рекомендуется, потому что basic_string не предназначен для (отсутствие виртуальных членов и т.д.). Если вам действительно нужен действительно собственный тип, например std:: basic_string < my_char_type > напишите специальную специализацию для этого.
Новый стандарт С++ 0x определяет wstring_convert < > и wbuffer_convert < > для преобразования с std:: codecvt из узкой кодировки в широкую кодировку (например, UTF-8 в UCS2).
Visual Studio 2010 уже реализовала это, afaik.