Как алгоритм кодирования UTF-8 работает на 8-битных блоках (в JavaScript)? - PullRequest
0 голосов
/ 22 декабря 2019

Я смотрю на это :

function encodeCodePoint(codePoint) {
  if ((codePoint & 0xFFFFFF80) == 0) { // 1-byte sequence
    return stringFromCharCode(codePoint);
  }
  var symbol = '';
  if ((codePoint & 0xFFFFF800) == 0) { // 2-byte sequence
    symbol = stringFromCharCode(((codePoint >> 6) & 0x1F) | 0xC0);
  }
  else if ((codePoint & 0xFFFF0000) == 0) { // 3-byte sequence
    checkScalarValue(codePoint);
    symbol = stringFromCharCode(((codePoint >> 12) & 0x0F) | 0xE0);
    symbol += createByte(codePoint, 6);
  }
  else if ((codePoint & 0xFFE00000) == 0) { // 4-byte sequence
    symbol = stringFromCharCode(((codePoint >> 18) & 0x07) | 0xF0);
    symbol += createByte(codePoint, 12);
    symbol += createByte(codePoint, 6);
  }
  symbol += stringFromCharCode((codePoint & 0x3F) | 0x80);
  return symbol;
}

, которое в JavaScript, кажется, использует тот факт, что числа в JavaScript (я думаю) что-то около 32длинойТаким образом, он выполняет некоторые битовые манипуляции, с которыми я не знаком, и получает закодированное значение. То же самое с функцией decode:

function decodeSymbol() {
  var byte1;
  var byte2;
  var byte3;
  var byte4;
  var codePoint;

  if (byteIndex > byteCount) {
    throw Error('Invalid byte index');
  }

  if (byteIndex == byteCount) {
    return false;
  }

  // Read first byte
  byte1 = byteArray[byteIndex] & 0xFF;
  byteIndex++;

  // 1-byte sequence (no continuation bytes)
  if ((byte1 & 0x80) == 0) {
    return byte1;
  }

  // 2-byte sequence
  if ((byte1 & 0xE0) == 0xC0) {
    byte2 = readContinuationByte();
    codePoint = ((byte1 & 0x1F) << 6) | byte2;
    if (codePoint >= 0x80) {
      return codePoint;
    } else {
      throw Error('Invalid continuation byte');
    }
  }

  // 3-byte sequence (may include unpaired surrogates)
  if ((byte1 & 0xF0) == 0xE0) {
    byte2 = readContinuationByte();
    byte3 = readContinuationByte();
    codePoint = ((byte1 & 0x0F) << 12) | (byte2 << 6) | byte3;
    if (codePoint >= 0x0800) {
      checkScalarValue(codePoint);
      return codePoint;
    } else {
      throw Error('Invalid continuation byte');
    }
  }

  // 4-byte sequence
  if ((byte1 & 0xF8) == 0xF0) {
    byte2 = readContinuationByte();
    byte3 = readContinuationByte();
    byte4 = readContinuationByte();
    codePoint = ((byte1 & 0x07) << 0x12) | (byte2 << 0x0C) |
      (byte3 << 0x06) | byte4;
    if (codePoint >= 0x010000 && codePoint <= 0x10FFFF) {
      return codePoint;
    }
  }

  throw Error('Invalid UTF-8 detected');
}

По сути, я не совсем читаю этот код и не могу точно сказать, что происходит. Интересно, может ли тот, кто лучше разбирается в битовых манипуляциях или обладает знаниями в области кодирования UTF-8, мог бы на высоком уровне описать, что является входом и выходом от кодирования и декодирования, и очень примерно, как он идет от входа к выходу для каждого,Я пытаюсь создать кодировщик / декодер utf-8 и не вижу точно, как 8-битный поток разбивается на куски от 1 до 4 байтов, отчасти потому, что, как мне кажется, мешает 32-битное целое число JavaScript. Но мне кажется, что вот что происходит:

Декодирование:

  • У нас есть 8-битный (1-байтовый) поток данных.
  • Мыполучить байт
  • Мы проверяем, находится ли этот байт в каком-то определенном диапазоне (чего я не знаю)
  • Если он находится в некотором диапазоне, то мы знаем, что следует дополнительный байт,или что-то в этом роде.
  • Затем мы собираем все байты для символа ...
  • И в случае с JavaScript конвертируем его в целое число, а затем String.fromCharCode(integer).

Чего мне не хватает, так это того, как именно он идет от 1-байтовой последовательности до 4-х байтов, как он выполняет эту часть?

Кодировка:

  • Это зависит от языка / архитектуры, так как некоторые архитектуры будут иметь целые числа 16, 32 или 64 бита (... я предполагаю ...).
  • В случае JavaScriptвозьмите 32-разрядное целое число и выполните магию манипуляции с битами, чтобы извлечь от 1 до 4 байт для этого символа. Откуда он знает, сколько байтов получить ???
  • Повторяйте, пока у вас не будет массива байтов.

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

1 Ответ

1 голос
/ 22 декабря 2019

JS целые числа имеют 32-битные бинарные операторы, поэтому вы можете безопасно работать с 4 x 8-битными (4 байтами) в одном единственном числе. Это то, что ваш декодер получает в качестве параметра.


Кодировка UTF-8 имеет переменный размер. Если кодовая точка займет всего 7 бит (= ASCII), то она уместится в один байт, который имеет начальный ноль, чтобы указать, что у него есть только один байт:

  0XXXXXXXX

Теперь, чтобы проверить, является ли кодовая точкатолько один байт, можно проверить, есть ли бит, установленный где-то в старших байтах. Это можно сделать, сравнив кодовую точку с 0xFFFFF80, в котором установлены все биты, кроме последних 8. Таким образом, если поразрядно и получается что-то неравное 0, где-то в верхних байтах установлен бит.

  1111111111111111111110000000 &
                      0XXXXXXX
   = 0

Теперь, если имеется более 7 бит, первый байт содержит количество байтов, все последующие байты содержат последовательность 01 в начале, для 4 байтов, которые будут:

  11110XXX 10XXXXXX 10XXXXXX 10XXXXXX

Теперь, чтобы получить здесь верхние 8 кодированных битов, например, можно сместить права на 18:

  1110XXX 10XXXXX
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...