Ответ 1
Глоссарий Unicode
Unicode - это обширная и сложная тема. Я не хочу пробираться слишком глубоко туда, однако необходим быстрый глоссарий:
- Кодовые точки: кодовые точки являются основными строительными блоками Юникода, кодовая точка представляет собой целое число, отображаемое в значении. Целочисленная часть вписывается в 32 бита (ну, на самом деле 24 бита), а смысл может быть буквой, диакритикой, пробелом, знаком, смайликом, наполовину флагом... и даже может быть " следующая часть читается справа налево ".
- Кластеры Grapheme: Grapheme Clusters - это группы семантически связанных кодовых точек, например, флаг в unicode представлен объединением двух кодовых точек; каждый из этих двух, по отдельности, не имеет никакого значения, но связан вместе в кластере Графем, они представляют собой флаг. Grapheme Clusters также используются для сопряжения буквы с диакритикой в некоторых сценариях.
Это основная часть Unicode. Различие между Code Point и Grapheme Cluster может быть в основном затушевано, потому что для большинства современных языков каждый "символ" отображается в единую кодовую точку (имеются специальные акцентированные формы для обычно используемых буквенных + диакритических комбинаций). Тем не менее, если вы рискуете смайлами, флагами и т.д.... тогда вам, возможно, придется обратить внимание на различие.
UTF Primer
Затем необходимо закодировать серию кодовых точек Юникода; общие кодировки - 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::u32string
(akastd::basic_string<char32_t>
). - Представление in-memory (
std::string
илиstd::wstring
) не зависит от представления на диске (UTF-8, UTF-16 или UTF-32), поэтому подготовьтесь к необходимости конвертировать на границе (чтение и письмо). - В то время как 32-бит
wchar_t
гарантирует, что блок кода представляет собой полную точку кода, он по-прежнему не представляет собой полный кластер Grapheme.
Если вы только читаете или составляете строки, у вас не должно быть никаких проблем с std::string
или std::wstring
.
Проблемы начинаются, когда вы начинаете нарезку и нарезку, тогда вы должны обратить внимание на (1) границы границы кода (в UTF-8 или UTF-16) и (2) границы Графемных кластеров. Первое может быть легко обработано самостоятельно, последнее требует использования библиотеки Unicode.
Выбор std::string
или std::u32string
?
Если производительность является проблемой, вероятно, что std::string
будет работать лучше из-за меньшего объема памяти; хотя тяжелое использование китайцев может изменить сделку. Как всегда, профиль.
Если Grapheme Clusters не проблема, то std::u32string
имеет преимущество в упрощении: 1 Code Unit → 1 Code Point означает, что вы не можете случайно разделить std::basic_string
очки, и все функции 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:]
), поскольку в зависимости от аромата и реализации регулярного выражения он может или не может совпадать с символами Unicode.
Аналогичным образом, будьте осторожны с применением повторителей к "персонажам", отличным от ASCII, "哈?"
может считать только последний байт необязательным; используйте круглые скобки для четкого определения повторяющейся последовательности байтов в таких случаях: "(哈)?"
,
1 Ключевыми понятиями для поиска являются нормализация и сопоставление; это влияет на все операции сравнения. std::string
всегда будет сравнивать (и, следовательно, сортировать) байты по байтам, независимо от правил сравнения, специфичных для языка или использования. Если вам нужно обрабатывать полную нормализацию/сопоставление, вам нужна полная библиотека Unicode, такая как ICU.