Форум программистов, компьютерный форум, киберфорум
mr_dramm
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  

Кратко о кодировании битов в utf8

Запись от mr_dramm размещена 26.12.2023 в 20:16
Показов 1673 Комментарии 0
Метки javascript, unicode

utf8 - стандарт кодирования символов, позволяющий более компактно хранить и передавать символы Юникода, используя переменное количество байт (от 1 до 4), и обеспечивающий полную обратную совместимость с 7-битной кодировкой ASCII.

рассмотрим, как распределяются биты в символах от 1 до 4х байт. для этого воспользуемся таблицей Table 3-6. UTF-8 Bit Distribution это основной стандарт и там ее можно найти странице 125 или через поиск.

Я ее немного дополнил значениями в десятичной и шестнадцатеричной системе и посчитал сколько старших символов и полезных символов для кодирования символа. В документации первые биты называются first second third fourth я их просто назвал major для упрощения, они нужны чтобы не допускать ошибок кодирования символов, code bit - это сколько битов остается на кодирование конкретного символа.

Также код символа там называется кодпоинт — codepoint, кодовая точка — в контексте кодирования символов — числовое значение, соответствующее определенному символу.

- 1 byte: codepoint<128 bin 0_xxxxxxx hex 7F major bits 1 + 7 code bit - Латинские символы и спец символы control
Остальные интернациальные кодировки и спец символы
- 2 byte: dec 128<codepoint<2048 bin 110_xxxxx 10_xxxxxx hex max 7FF major bits 5 + 11 code bit
- 3 byte: dec 2048<codepoint<65536 bin 1110_xxxx 10_xxxxxx 10_xxxxxx hex max FFFF major bits 8 + 16 code bit
Эмоджи и спецсимволы
- 4 byte: dec 65536<codepoint<2097151 bin 11110_xxx 10_xxxxxx 10_xxxxxx 10_xxxxxx hex max 1FFFFF major bits 11 + 21 code bit

тут можно посмотреть код каждого символа, очень удобно

Теперь перейдем у практической части рассмотрим пример кодирования и декодирования буквы "Ц"

Из описания выше должно стать понятно, как определить сколько этот символ занимает байт. Для этого мы получаем код символа

JavaScript
1
"Ц".charCodeAt() // 1062
1062 это 2 байта

Когда выполняется декодирование старшие биты удаляются

JavaScript
1
2
3
4
5
6
7
8
9
function decode(ucode) {
    // hex 0x1f00 bin 000_1 1111 0000 0000 - маска для второго байта
    // hex 0x3f bin 00_11 1111  - маска для первого байта
    // >> 2 нужна чтобы биты заняли позиции старших битов, которые мы удалили
    let code = ((ucode & 0x1f00) >> 2) | (ucode & 0x3f);
    return String.fromCharCode(code);
}
 
console.log(decode(0xd0a6)); // Ц
При кодировании добавляются

JavaScript
1
2
3
4
5
6
7
8
9
10
11
function encode(char) {
    const code = char.charCodeAt(0);
    // hex 0x80 bin 10_00 0000 - добавляем старшие биты для первого байта
    // hex 0x3f bin 0011 1111
    // hex 0x7c0 bin 0111 1100 0000
    // hex 0xc000 110_0 0000 0000 0000  - добавляем старшие биты для второго байта
    let ucode = ((code & 0x7c0) << 2) | 0xc000 | ((code & 0x003f) | 0x80);
    return "0x" + ucode.toString(16);
}
 
console.log(encode("Ц")); // 0xd0a6
UPD 2024 01 02

Eva Rosalene, предложила очень простое рабочее решение

Господи. Зачем вы разбираете Юникод руками. Разбейте входную чушь на байты и прогоните через TextDecoder, делов-то.
пруф

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function parseSegment(segment) {
  let result = [];
  for (let i = 0; i < segment.length; i += 2) {
    const hexByte = segment.slice(i, i + 2);
    result.push(parseInt(hexByte, 16));
  }
  return result;
}
 
function parse(data) {
  const bytes = data
    .split('|')
    .map(i => i.trim())
    .filter(i => i.length > 0)
    .flatMap(parseSegment);
  const u8arr = new Uint8Array(bytes);
  return new TextDecoder().decode(u8arr);
}
 
console.log(parse("76|d0a6|d0bc|6e")); // vЦмn
Это фактически универсальный конвертер в несколько строчек кода.
Этот пример очень хорошо демонстрирует зачем нужны major биты в начале каждого байта, о которых писалось ранее.

- 1 byte: codepoint<128 bin 0_xxxxxxx hex 7F major bits 1 + 7 code bit - Латинские символы и спец символы control
Остальные интернациальные кодировки и спец символы
- 2 byte: dec 128<codepoint<2048 bin 110_xxxxx 10_xxxxxx hex max 7FF major bits 5 + 11 code bit
- 3 byte: dec 2048<codepoint<65536 bin 1110_xxxx 10_xxxxxx 10_xxxxxx hex max FFFF major bits 8 + 16 code bit
Эмоджи и спецсимволы
- 4 byte: dec 65536<codepoint<2097151 bin 11110_xxx 10_xxxxxx 10_xxxxxx 10_xxxxxx hex max 1FFFFF major bits 11 + 21 code bit

В Uint8Array байты хранятся непрерывной последовательностью, но TextDecoder справился понял какие символы состоят из одного байта и какие из двух

Для Node js вместо TextEncoder может быть использован метод toString встроенного объекта Buffer

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function parseSegment(segment) {
  const result = [];
  for (let i = 0; i < segment.length; i += 2) {
    const hexByte = segment.slice(i, i + 2);
    result.push(parseInt(hexByte, 16));
  }
  return Buffer.from(result).toString('utf8');
}
 
function parse(data) {
  const bytes = data
    .split('|')
    .map(i => i.trim())
    .filter(i => i.length > 0)
    .flatMap(parseSegment);
  return bytes;
}
 
console.log(parse("76|d0a6|d0bc|6e")); // [ 'v', 'Ц', 'м', 'n' ]
Метки javascript, unicode
Размещено в character encoding, unicode
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 0
Комментарии
 
Новые блоги и статьи
Когда логика программы не спасает от человеческих ошибок
Maks 18.08.2026
В последнее время всё чаще и чаще сталкиваюсь с таким явлением, как абсолютная невнимательность (или глупость) пользователей. Проявляется это чаще всего на работе в коллективе. Допустим, человек с. . .
Лето уходит
kumehtar 17.08.2026
Мысли в слух
kumehtar 17.08.2026
Забавно, насколько сейчас стала доступна информация. Например о магии, духовном развитии, медитациях, и других подобных направлениях, ранее зачастую тайных, передаваемых от учителя к ученику. Хотя. . .
Перемещение строк из ТЧ в другой документ с учетом текущего пробега
Maks 17.08.2026
Реализация из решения ниже выполнена на примере нетипового документа "Автозапчасти", с ТЧ "Шины". За основу взят алгоритм отсюда: https:/ / www. cyberforum. ru/ blogs/ 359708/ 10838. html Задача: . . .
Саморегулирующийся социальный контракт для сервера cross-section.
Hrethgir 14.08.2026
С кодом конечно таких глубоких размышлений пока не было, впрочем я уже привык к алгоритмизации. Суть предмета записи: снова в диалоге с нейросетью (я взял пока себе ник для учётки админа - Rector). . . .
Часы электронные
Uhbif79 12.08.2026
Выкладываю программу часов. Программа позволяет: 1. Использовать системное время и дату, 2. Есть возможность вводить время и дату вручную. 3. Реализованы 2 будильника: начало и конец рабочего дня. . . .
Часы с будильником на основе класса QLCDNumber
Uhbif79 12.08.2026
Всем добрый день, выкладываю программу часов с будильником на основе класса QLCDNumber. Здесь я пробовал самостоятельно создавал классы, впервые столкнулся с видимостью переменной одного класса из. . .
Установка MinGW GCC 16.2 и CMake
8Observer8 10.08.2026
VK Видео: https:/ / vkvideo. ru/ video-240781534_456239017 YouTube: eY5-5PyI9NM Текстовая версия
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru