Строки ASCII и UTF-8 (или UCS-2 и UTF-16) в одном проекте C ++ - PullRequest
0 голосов
/ 22 января 2019

У нас есть проект, в котором по историческим причинам обработка строк является какофонией кодировок и представлений; у нас определенно есть места, которые могут надежно обрабатывать только ASCII, в некоторых местах, вероятно, используется UTF-8, в некоторых местах на периферии, которые, как я подозреваю, используется 8-битное кодирование для конкретной платформы (разное, конечно, для разных целевых платформ), различные места, предназначенные для UCS-2, и, возможно, также те, которые были бы рады работать на UTF-16 - все они иногда передаются как строки в стиле C (char*, CHAR16*), а иногда как строки C ++ ( std::string, std::basic_string<CHAR16>). Конечно, с точки зрения документации очень мало.

В качестве первого шага к устранению этой путаницы я хочу настроить систему типов, использующую действительно разные типы для разных кодировок.

Одна мысль, которая пришла мне в голову, состояла в том, чтобы использовать, например. signed char в качестве основы для строк ASCII и unsigned char для строк UTF-8, а также char16_t для UCS-2 и short для UTF-16 (или что-то в этом духе), но это будет означать, что I не сможет напрямую использовать строковые литералы. Кроме того, возможность просто передавать строки ASCII функциям, ожидающим UTF-8 (но не наоборот), была бы изящной.

У вас есть какие-нибудь умные предложения о том, как это сделать, или, может быть, даже рабочий код?

Код должен быть совместим с C ++ 11.

Пожалуйста, воздержитесь от любых ответов в духе «просто постоянно используйте UTF-8», потому что это в любом случае моя конечная цель; скорее, речь идет о создании инструмента, который, как мне кажется, очень мне поможет.

- приложение -

Вероятно, я должен был упомянуть, что, как я полагаю, у нас уже есть проблемы, когда строковое кодирование не выстраивается должным образом, например Строки UTF-16 передаются в функции, которые могут обрабатывать только строки UCS-2, или 8-разрядные строки, специфичные для платформы, которые передаются функциям, которые ожидают строки ASCII. Буквально вчера я обнаружил выделенные функции преобразования, содержащие в своем названии "ASCII", которые фактически будут преобразовывать в / из Latin-1 вместо ASCII.

Ответы [ 2 ]

0 голосов
/ 24 января 2019

Я думаю, что я на что-то, по крайней мере, что касается строк C ++ (std::string, std::basic_string<chat16_t>);здесь ключом может быть использование нестандартных символов , например:

using ASCII  = char;
using LATIN1 = char;
using UTF8   = char;
using UCS2   = char16_t;
using UTF16  = char16_t;

class ASCIICharTraits  : public std::char_traits<ASCII>  {};
class Latin1CharTraits : public std::char_traits<LATIN1> {};
class UTF8CharTraits   : public std::char_traits<UTF8>   {};
class UCS2CharTraits   : public std::char_traits<UCS2>   {};
class UTF16CharTraits  : public std::char_traits<UTF16>  {};

using ASCIIString  = std::basic_string<ASCII,  ASCIICharTraits>;
using Latin1String = std::basic_string<LATIN1, Latin1CharTraits>;
using UTF8String   = std::basic_string<UTF8,   UTF8CharTraits>;
using UCS2String   = std::basic_string<UCS2,   UCS2CharTraits>;
using UTF16String  = std::basic_string<UTF16,  UTF16CharTraits>;

Использование различных типов в качестве параметра traits в шаблоне std::basic_string гарантирует, чтоСтроковые типы также обрабатываются компилятором как отдельные типы, предотвращая любое смешение несовместимо закодированных строк C ++ без необходимости написания оболочки-оболочки.

Обратите внимание, что для того, чтобы это работало, пользовательские типы признаков должны быть разделены на подклассы,не просто псевдоним.(Теоретически я мог бы написать новые типы черт с нуля, но наследование от std::char_traits значительно облегчает работу и должно обеспечить совместимость двоичного кода, позволяющую реализовать тривиальные преобразования (например, из ASCII в Latin-1 или UTF-8).) с помощью простого reinterpret_cast.

(Интересный факт: насколько мне известно, этот механизм должен работать даже со старым добрым C ++ 03, при условии, что предложения using заменены соответствующими typedef s.)

0 голосов
/ 23 января 2019

Рекомендую стандартное предложение: сэндвич-метод.

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

Только на слоях вы будете декодировать (вводить) или кодировать (выводить). Также должно быть понятно, почему вы выбираете одну кодировку. Запись в файл? UTF-8 хорош (ASCII - это подмножество, поэтому оставьте его как UTF-8). В такой части вы также делаете проверку ввода. Это должен быть номер? Убедитесь, что они являются номерами Unicode. и т. д. Валидация и кодирование данных (валидация) должны быть как можно ближе к чтению ввода. Для вывода используйте то же правило (но в этом случае не должно быть проверки).

Так что теперь вы можете поставить префикс истинных строк с некоторым префиксом (попробуйте что-то уникальное) и попытаться найти, где вы кодируете / декодируете. Попробуйте перенести такую ​​кодировку на внешние слои. Когда вы закончите, вы удалите префикс.

Вы можете использовать другие префиксы для других кодировок (только временно). Также в этом случае попробуйте что-то уникальное. Запутайтесь в именах переменных, а не в типах.

В качестве альтернативы, я думаю, вы можете аннотировать переменные и использовать внешние инструменты, чтобы проверить, что некоторые аннотации не смешиваются. Ядро Linux использует нечто подобное (например, для различения пространства пользователя и указателей ядра). Я думаю, что это излишне для вашей программы.

Почему бутерброд? Теперь вы, наверное, много знаете о UTF-8, UCS-2, UTF-16 и т. Д. Но это заняло время. Следующий сотрудник может не знать всех таких деталей, и это может вызвать проблемы в долгосрочной перспективе. Мы также используем целые числа, не беспокоясь о том, является ли оно одним дополнением, двумя дополнением или знаковым битом, но когда мы записываем данные. Сделайте то же самое для строк. Сохраняйте семантику и забудьте кодировку внутри программы. Только внешний слой должен справиться с этим.

...