Правильное использование хранилища строк в C и С++
Популярные разработчики программного обеспечения и компании (Joel Spolsky, Программное обеспечение Fog Creek) имеют тенденцию использовать wchar_t для хранения символов Unicode при написании кода C или С++. Когда и как следует использовать char и wchar_t в отношении хороших методов кодирования?
Меня особенно интересует соответствие POSIX при написании программного обеспечения, которое использует Unicode.
При использовании wchar_t вы можете искать символы в массиве широких символов на основе каждого элемента или каждого элемента массива:
/* C code fragment */
const wchar_t *overlord = L"ov€rlord";
if (overlord[2] == L'€')
wprintf(L"Character comparison on a per-character basis.\n");
Как вы можете сравнивать байты Unicode (или символы) при использовании char?
До сих пор мой предпочтительный способ сравнения строк и символов типа char в C часто выглядит так:
/* C code fragment */
const char *mail[] = { "ov€[email protected]", "ov€[email protected]" };
if (mail[0][2] == mail[1][2] && mail[0][3] == mail[1][3] && mail[0][3] == mail[1][3])
printf("%s\n%zu", *mail, strlen(*mail));
Этот метод проверяет эквивалент байта символа юникода. Символ Unicode Euro € занимает 3 байта. Поэтому нужно сравнить три байта массива char, чтобы узнать, соответствуют ли символы Unicode. Часто вам нужно знать размер символа или строки, которую вы хотите сравнить, и биты, которые она создает для решения. Это не похоже на хороший способ обработки Unicode. Есть ли лучший способ сравнения строк и символьных элементов типа char?
Кроме того, при использовании wchar_t, как вы можете сканировать содержимое файла в массив? Функция fread не дает достоверных результатов.
Ответы
Ответ 1
Если вы знаете, что имеете дело с unicode, то не подходят char
и wchar_t
, так как их размеры определяются компилятором/платформой. Например, wchar_t
- 2 байта в Windows (MSVC), но 4 байта в Linux (GCC). Стандарты C11 и С++ 11 были немного более строгими и определяют два новых типа символов (char16_t
и char32_t
) с соответствующими литеральными префиксами для создания строк UTF- {8, 16, 32}.
Если вам нужно хранить и манипулировать символами юникода, вы должны использовать библиотеку, предназначенную для задания, поскольку ни один из языков языка pre-C11 и pre-С++ 11 не был написан с учетом unicode. Есть несколько, чтобы выбрать из, но ICU (и поддерживает C, С++ и Java).
Ответ 2
Меня особенно интересует соблюдение POSIX при написании программного обеспечения который использует Unicode.
В этом случае вы, вероятно, захотите использовать UTF-8 (с char
) в качестве предпочтительного типа строки Юникода. POSIX не имеет большого количества функций для работы с wchar_t
— что в основном вещь Windows.
Этот метод проверяет эквивалент байта символа юникода. Unicode Euro symbol € занимает 3 байта. Поэтому нужно сравнить три байта массива char, чтобы узнать, соответствуют ли символы Юникода. Часто вам нужно знать размер символа или строки, которую вы хотите сравнить и биты, которые он создает для работы решения.
Нет, нет. Вы просто сравниваете байты. Iff соответствует байтам, строки соответствуют. strcmp
работает также с UTF-8, как и с любой другой кодировкой.
Если вы не хотите что-то вроде нечувствительного к регистру или не учитывающего акцента сравнения, в этом случае вам понадобится соответствующая библиотека Unicode.
Ответ 3
Вы никогда не должны сравнивать байты или даже точки кода, чтобы определить, равны ли строки. Это из-за большого количества строк может быть идентичным с точки зрения пользователя, не будучи идентичным с точки зрения кодовой точки.