2021-09-28 09:00:52
Чем отличаются кодировки?
Продолжаем тему прошлой недели и снова поговорим о классе
String. В java 9 вышло интересное обновление - компактные строки. Чтобы лучше понять, в чём была проблема и как она решена, разберём в этом посте отличия между кодировками. А в четверг обсудим уже сами компактные строки.
Итак, символы хранятся в памяти в виде чисел. Кодировки отвечают за формат хранения и правила перевода символов в числа и обратно. Кодировки условно делятся на две группы:
ASCII-based
Unicode-based
ASCII
В большинстве ASCII кодировок символ занимает 1 байт и содержит число от 0 до 256. Первые 128 значений транслируются одинаково во всех кодировках:
0-31: управляющие последовательности - перенос строки, конец файла и т.д.
32-127: латинский алфавит, цифры, знаки препинания
Значения 128-255 отображаются на специфичные символы языков. Разные кодировки - разные наборы символов:
Кириллица: ISO-8859-5, Windows-1251
Греческий алфавит: ISO-8859-7, Windows-1253
Исландские символы: OEM 861
200 может стать Ш, Θ, È или чем-то ещё. Фраза
Я люблю Java в другой кодировке отобразится как
Ď ŰîŃŰî Java.
Компактный формат: 1 символ — 1 байт
Всего 256 значений — нет места для эмодзи
Неоднозначность трактовки
Нельзя использовать украинский и норвежский язык в одном тексте
Unicode
В основе преобразований лежит гигантская таблица с большинством символов, которые используются в мире. Первые 127 символов полностью совпадают с ASCII.
Но ASCII-кодировки не умеют читать символы больше 255. Если подсунуть им юникод, то непонятные значения превратятся в и текст
Я люблю Java отобразится как
? ????? Java.
Как хранится юникод.
Ранние версии используют отображение 1 к 1. Все символы хранятся одинаково и занимают одинаковое количество памяти.
Одна из первых кодировок UCS-2 хранила один символ в двух байтах. После ASCII с их диапазоном 0-256 казалось, что диапазона 0-65536 хватит навсегда.
Со временем в таблицу добавилось больше символов и встал вопрос об эффективном хранении данных. Сегодня, чтобы однозначно представить символ юникода нужно 32 бита — так символы хранятся в UTF-32:
Прямое отображение
Простота обработки
Очень много символов
Неэффективный расход памяти — если использовать только латиницу с кодами типа 0..045 и 0...077, три четверти памяти будет занято нулями.
Чтобы решить проблему выше, появились кодировки с переменной длиной: UTF-8 и UTF-16.
Они используют не отображение 1 к 1, а схему с флажками и вычислениями.
В UTF-8 символ занимает 1, 2, 3 или 4 байта. В UTF-16 популярные символы занимают 2 байта, а непопулярные - 4.
Экономный расход памяти для латинских символов
Обработка и поиск происходят чуть медленнее, тк надо делать преобразования
Отметка длины находится в первых 2 битах и уменьшает диапазон значений
Если в структуре 2 или больше байтов, то одни процессоры быстрее считывают их в прямом порядке, а другие — в обратном. Поэтому у UTF-16 и UTF-32 могут быть приставки LE или BE: Little/Big endian.
Что в java. В ранних версиях для char использовалась UCS-2, один символ занимал 2 байта. Затем java перешла на UTF-16 с переменной длиной.
Ну а что с этим не так, и как обстоят дела в java 9 - поговорим в следующем посте.
1.9K views06:00