Ответ
Unicode — это универсальный стандарт кодирования символов, который ставит в соответствие каждому символу из большинства письменных систем мира уникальный числовой код (кодовую точку, code point). В отличие от ASCII (128 символов), Unicode охватывает более 140 000 символов, включая исторические шрифты, эмодзи и специальные знаки.
Основные кодировки (форматы хранения байтов):
- UTF-8: Переменная длина (1-4 байта). Обратно совместима с ASCII (первые 128 символов кодируются одним байтом). Стандарт для веба и многих систем. Является кодировкой по умолчанию для строковых литералов во многих компиляторах.
- UTF-16: Использует 2 или 4 байта (суррогатные пары для символов за пределами Basic Multilingual Plane). Нативный для Windows API и Java.
- UTF-32: Фиксированная длина (4 байта на кодовую точку). Прост для обработки, но неэффективен по памяти.
Работа с Unicode в современном C++ (C++11 и выше):
#include <iostream>
#include <string>
#include <locale>
#include <codecvt> // Для конвертации (устарело в C++17, но пока используется)
int main() {
// Строковые литералы с префиксами:
std::string utf8_str = u8"Привет, 世界! 😊"; // UTF-8 (char)
std::u16string utf16_str = u"Привет, 世界! 😊"; // UTF-16 (char16_t)
std::u32string utf32_str = U"Привет, 世界! 😊"; // UTF-32 (char32_t)
std::wstring wide_str = L"Привет, 世界! 😊"; // Широкая строка (wchar_t, зависит от платформы)
std::cout << "UTF-8 output: " << utf8_str << std::endl;
// Конвертация UTF-8 в UTF-16 (используя устаревший, но пока распространенный codecvt)
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> converter;
std::u16string converted = converter.from_bytes(utf8_str);
// **Важно:** Для корректного вывода в консоль Windows может потребоваться
// изменить кодовую страницу консоли или использовать API WriteConsoleW.
// На Linux/macOS с UTF-8 локалью вывод обычно работает корректно.
// Итерация по кодовым точкам UTF-8 (упрощенно):
for (char c : utf8_str) {
// Но так мы итерируем по байтам, а не по символам!
// Для посимвольной обработки нужны библиотеки (ICU, Boost.Nowide) или C++20 <text_encoding>.
}
return 0;
}
Проблемы и рекомендации для C++:
std::stringиstd::wstringне знают о кодировке. Они просто хранят последовательностиchar/wchar_t. Ответственность за корректную интерпретацию лежит на программисте.- Консольный ввод/вывод может некорректно отображать Unicode в зависимости от настроек терминала/консоли.
- Для сложных операций (нормализация, разбиение на графемы, сортировка) используйте специализированные библиотеки, такие как International Components for Unicode (ICU).
- C++20 вводит новые типы (
std::u8string) и улучшенную поддержку текста, но полная библиотека пока не реализована во всех компиляторах.
Правило для современных кроссплатформенных проектов: Храните и обрабатывайте текст внутри программы в UTF-8 (используя std::string), конвертируя в другие кодировки только на границах ввода/вывода (файлы, сеть, UI).
Ответ 18+ 🔞
Бля, ну вот смотри, с этим Unicode история такая, что ядрёна вошь, честно. Вроде бы простая идея — каждой букве, смайлику или иероглифу дать свой уникальный номер, чтобы компы не путались. Но как это всё реализовано, ёпта... Это ж овердохуища правил, исключений и подводных камней.
Представь себе ASCII — это как маленькая деревня, там 128 домиков-символов, всем хватает. А Unicode — это хуй с горы, мегаполис на 140+ тысяч жителей, где у каждого паспорт — это кодовая точка (code point). И живут там все: от древнегреческих букв до этих ваших ебушки-воробушки эмодзи.
А вот где начинается пиздец — так это в транспорте, то есть в кодировках. Как эти номера в байты упаковать?
- UTF-8: Хитрый, как жопа. Использует от 1 до 4 байтов. Для латиницы — один байт, полная совместимость со старой ASCII. А вот для кириллицы или иероглифов — уже два-три. Для эмодзи — все четыре, бля. Это стандарт де-факто для интернета, и доверия к нему — ебать ноль, потому что все его используют.
- UTF-16: Прямолинейный, как манда с ушами. Почти всегда по 2 байта на символ, но для редких символов (тех же эмодзи) может выехать сюрприз — суррогатная пара, то есть 4 байта. Это родная кодировка для Windows и Java. Подозрение ебать чувствую к этой неконсистентности.
- UTF-32: Тупой и честный. Берёт и каждому символу отдаёт по 4 байта, пофиг на важность. Прост для перебора, но памяти жрёт, как не в себя. Редко где используется.
Теперь про C++. Тут волнение ебать начинается. Компилятор вроде как умный, но строка (std::string) — она же нихуя не знает про кодировку! Это просто мешок с байтами. Ответственность — полностью на тебе, чувак.
Смотри, как это выглядит в коде (C++11 и выше):
#include <iostream>
#include <string>
#include <locale>
#include <codecvt> // Эта штука, бля, устарела, но все ещё везде используется!
int main() {
// Вот так объявляешь строки в разных кодировках
std::string utf8_str = u8"Привет, 世界! 😊"; // UTF-8, обычные char
std::u16string utf16_str = u"Привет, 世界! 😊"; // UTF-16, char16_t
std::u32string utf32_str = U"Привет, 世界! 😊"; // UTF-32, char32_t
std::wstring wide_str = L"Привет, 世界! 😊"; // Широкая строка. А вот её размер — это хуй в пальто, зависит от системы.
std::cout << "Пытаемся вывести UTF-8: " << utf8_str << std::endl;
// И вот тут может случиться "ни хуя себе". Если консоль не в UTF-8, увидишь кракозябры.
// Конвертация из UTF-8 в UTF-16 (старым, устаревшим методом)
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> converter;
std::u16string converted = converter.from_bytes(utf8_str);
// ВАЖНО: Вывод в консоль Windows — это отдельный ад.
// Нужно или кодовую страницу менять, или WriteConsoleW вызывать.
// На нормальных системах (Linux/macOS) с UTF-8 локалью обычно работает.
// Хочешь пройтись по символам UTF-8? Забудь про простой for по char!
for (char c : utf8_str) { // Тут ты итерируешься по БАЙТАМ, а не по символам!
// Для кириллического 'П' (которая 2 байта) ты сделаешь две итерации!
// Это пиздопроебибна ошибка новичков.
}
// Для нормального посимвольного разбора нужны библиотеки вроде ICU.
return 0;
}
Итоговые рекомендации, чтобы не сойти с ума:
- Главное правило, золотое: Внутри своей программы всё храни в UTF-8 (в
std::string). Это твой единый язык. Всё остальное — это для общения с внешним миром. - Конвертируй только на границах. Получил из файла или сети в UTF-16? Сразу переведи в UTF-8 для работы. Отдаёшь в Windows API? Сконвертируй обратно в UTF-16 в последний момент.
- Консоль — твой враг. Не рассчитывай, что
std::coutвсё красиво покажет. Это отдельная боль. - Для серьёзных дел (сортировка, поиск, разбиение на слоги) бери ICU. Стандартная библиотека C++ с этим справляется хуже, чем мартышлюшка с интегралами.
- C++20 обещает новые типы (
std::u8string) и лучшее управление текстом, но пока это всё сыро и не везде работает. Так что пока живём по старым, проверенным граблям.
Короче, Unicode — это мощно и необходимо, но будь готов, что иногда придётся материться и лезть в документацию глубже, чем обычно.