Глоссарий Unicode
Unicode - обширная и сложная тема.Я не хочу вдаваться в подробности, но необходим краткий глоссарий:
- Кодовые точки : кодовые точки являются основными строительными блоками Unicode, кодовая точка простоцелое число, сопоставленное с , означающим .Целочисленная часть умещается в 32 бита (ну, на самом деле, 24 бита), и значение может быть буквой, диакритическим знаком, пробелом, знаком, смайликом, половиной флага ... и даже может бытьследующая часть читается справа налево ".
- Кластеры графем : Кластеры графем - это группы семантически связанных кодовых точек, например, флаг в юникоде представлен связыванием двух кодовых точек;каждый из этих двух, в отдельности, не имеет смысла, но связан вместе в кластере графем, они представляют флаг.Кластеры графемы также используются для сопряжения букв с диакритическими знаками в некоторых сценариях.
Это основа Unicode.Различие между Code Point и Grapheme Cluster может быть в основном скрыто, потому что для большинства современных языков каждый «символ» сопоставляется с одной Code Point (существуют специальные акцентированные формы для часто используемых комбинаций буква + диакритический знак).Тем не менее, если вы решитесь на смайлики, флаги и т. Д., То вам, возможно, придется обратить внимание на это различие.
UTF Primer
Затем серия кодовых точек Unicodeдолжен быть закодирован;Общими кодировками являются UTF-8, UTF-16 и UTF-32, последние две существуют в формах Little-Endian и Big-Endian, всего 5 общих кодировок.
В UTF-X,X - это размер в битах кодовой единицы , каждая кодовая точка представлена в виде одной или нескольких кодовых единиц в зависимости от величины:
- UTF-8: от 1 до 4Единицы кода,
- UTF-16: 1 или 2 единицы кода,
- UTF-32: 1 единица кода.
std::string
и std::wstring
.
- Не используйте
std::wstring
, если вам нужна переносимость (wchar_t
- только 16 бит в Windows);используйте вместо этого std::u32string
(он же std::basic_string<char32_t>
). - Представление в памяти (
std::string
или std::wstring
) не зависит от представления на диске (UTF-8, UTF-16 или UTF-32), поэтому подготовьтесь к необходимости преобразования на границе (чтение и запись). - Хотя 32-битный
wchar_t
гарантирует, что единица кода представляет собой полную кодовую точку, она все равно не представляетполный Grapheme Cluster.
Если вы только читаете или сочиняете строки, у вас не должно быть мелких проблем с std::string
или std::wstring
.
Проблемы начинаются при запускенарезая кубиками, вы должны обратить внимание на (1) границы кодовой точки (в UTF-8 или UTF-16) и (2) границы графемных кластеров.Первый может быть обработан достаточно легко самостоятельно, последний требует использования библиотеки, поддерживающей Unicode.
Выбор std::string
или std::u32string
?
Если производительность является проблемой,вполне вероятно, что std::string
будет работать лучше из-за меньшего объема памяти;хотя интенсивное использование китайского языка может изменить сделку.Как всегда, профиль.
Если кластеры Grapheme не являются проблемой, то std::u32string
имеет преимущество в упрощении вещей: 1 единица кода -> 1 точка кода означает, что вы не можете случайно разделить точки кода и всефункции std::basic_string
работают "из коробки".
Если вы взаимодействуете с программным обеспечением, принимающим std::string
или char*
/ char const*
, тогда придерживайтесь std::string
, чтобы избежать обратного преобразования.В противном случае это будет боль.
UTF-8 в std::string
.
UTF-8 на самом деле довольно хорошо работает в std::string
.
Большинствооперации выполняются «из коробки», потому что кодировка UTF-8 является самосинхронизирующейся и обратно совместимой с ASCII.
Из-за способа кодирования кодовых точек поиск кодовой точки не может случайно совпадать с серединой другой кодовой точки:
str.find('\n')
работает, str.find("...")
работает для сопоставления байта за байтом 1 , str.find_first_of("\r\n")
работает при поиске символов ASCII .
Аналогично, regex
в основном работает из коробки.Поскольку последовательность символов ("haha"
) - это просто последовательность байтов ("哈"
), базовые шаблоны поиска должны работать из коробки.
Однако, с осторожностью относитесь к классам символов (таким как [:alphanum:]
), поскольку в зависимости от вида и реализации регулярного выражения оно может совпадать или не совпадать с символами Юникода.
Аналогично, с осторожностью относитесь к применению повторителей к не-ASCII "символам", "哈?"
может учитывать только последниенеобязательный байт;используйте скобки, чтобы четко очертить повторяющуюся последовательность байтов в таких случаях: "(哈)?"
.
1 Ключевыми понятиями для поиска являются нормализация и сопоставление;это влияет на все операции сравнения.std::string
всегда будет сравнивать (и, следовательно, сортировать) байты за байтом, без учета правил сравнения, специфичных для языка или использования.Если вам нужна полная нормализация / сопоставление, вам нужна полная библиотека Unicode, такая как ICU.