Как рассчитать целое число на основе последовательности байтов - PullRequest
0 голосов
/ 10 марта 2019

Итак, я пытаюсь понять математику при попытке перевести шестнадцатеричные escape-последовательности в целые числа.

Итак, если у меня есть строка "Ã", когда я делаю "Ã".encode('utf-8'), я получаю строку байтов, подобную этой "\xc3". ord("Ã") - 195. Математика - 16 * 12 + 3, что составляет 195. Вещи имеют смысл.

Но если у меня есть символ "é" - тогда шестнадцатеричная escape-последовательность в кодировке utf8 равна "\xc3\xa9 - и ord("é") равно 233. Как выполняется этот расчет? (a9 сам по себе равен 169, так что это явно не дополнение).

Аналогично этому 'Ĭ'.encode('utf-8'). Это дает b'\xc4\xac'. А ord('Ĭ') равно 300.

Может кто-нибудь объяснить здесь математику?

Ответы [ 4 ]

2 голосов
/ 10 марта 2019

Из документа:

ord (c)

Если задана строка, представляющая один символ Unicode, вернуть целое число, представляющее кодовую точку Unicode для этого символа.Например, ord ('a') возвращает целое число 97, а ord ('€') (знак евро) возвращает 8364. Это обратное значение для chr ().

Что возвращает ordэто кодовая точка Unicode символа - примерно число, позволяющее идентифицировать символ среди большого числа символов, известных в Unicode.

Когда вы кодируете свой символ с помощью UTF-8, вы представляете его с помощью последовательностибайтов, который не имеет прямого отношения к кодовой точке Unicode.Могут быть некоторые совпадения, в основном для символов ASCII, которые представлены последовательностью в один байт, но это не удастся для всех более «экзотических» символов.

Посмотрите на Абсолютный минимум каждого программного обеспеченияРазработчик, безусловно, должен знать о Unicode и наборах символов (без оправданий!) и страница википедии о UTF-8 .

2 голосов
/ 10 марта 2019

UTF-8 был разработан в соответствии с несколькими общими принципами проектирования / ограничениями.Важно понять эти принципы проектирования, чтобы понять, почему алгоритм кодирования UTF-8 таков, каков он есть.

  1. Обратная совместимость с ASCII: каждый символ ASCII должен иметь одинаковую кодировку в ASCIIи UTF-8.
  2. Обнаруживаемость не-ASCII-символов: ни один октет, который был бы действительной кодировкой ASCII-символа, не должен появляться в многооктетной последовательности кодирования не-ASCII-символа.
  3. Длина кодирования: длина последовательности многооктетного кодирования должна быть закодирована в первом октете, чтобы мы знали перед чтением всей последовательности многооктетного кодирования, какой длины она будет.Кроме того, человеку легко определить длину последовательности многооктетного кодирования.
  4. Откат / автоопределение: текст в одной из популярных 8-битных кодировок (например, ISO8859-15, Windows-1252) очень вряд ли содержит последовательности, которые являются действительными последовательностями многооктетного кодирования UTF-8, поэтому такие кодировки могут быть легко обнаружены и наоборот.
  5. Самосинхронизация: вы можетеначать декодирование в любом месте в середине потока UTF-8, и вам потребуется не более, чем до следующего символа ASCII или начала следующей последовательности многооктетного кодирования, чтобы начать декодирование допустимых символов.Если вы можете перемещаться назад в потоке, для поиска действительной начальной точки потребуется резервное копирование не более 3 октетов.
  6. Порядок сортировки: сортировка потоков UTF-8 по октетам автоматически приведет к порядку сортировки по кодам безнеобходимость декодировать поток.

Способ кодирования UTF-8 работает следующим образом:

  • Любой символ ASCII кодируется так же, как в ASCII, как одиноктет, начинающийся с 0 бита.
  • Любой не-ASCII символ кодируется как многооктетная последовательность.
  • Первый октет многооктетной последовательности кодирования начинается с битовой комбинации110, 1110 или 11110, где число 1 битов обозначает длину многооктетной последовательности, то есть многооктетная последовательность, начинающаяся с октета 1110xxxx, имеет длину 3 октета.
  • Любой дополнительный октет, который является частью многооктетной последовательности, начинается с битовой комбинации 10.
  • Кодовая точка Unicode кодируется в нефиксированные биты многооктетного кодированияsequence.

Вот пример: A имеет кодовую точку Unicode U + 0041.Поскольку это ASCII-символ, он будет просто закодирован так же, как и в ASCII, то есть в двоичном виде 01000001.

Знак евро имеет кодовую точку Unicode U + 20AC.Поскольку это не символ ASCII, его необходимо кодировать как многооктетную последовательность кодирования.Шестнадцатеричный 0x20AC в двоичном виде равен 10000010101100, поэтому для его представления требуется 14 бит.

Двухоктетная последовательность выглядит следующим образом: 110xxxxx 10xxxxxx, поэтому она дает нам только 11 бит.Поэтому нам нужна трехоктетная последовательность, которая выглядит следующим образом: 1110xxxx 10xxxxxx 10xxxxxx.Это дает нам 16 битов, что больше, чем нам нужно.Расширяемое нулями двоичное представление кодовой точки теперь просто упаковывается в x es:

11100010 10000010 10101100
^^^^00xx ^^xxxxxx ^^xxxxxx

Шестнадцатеричное представление этой цепочки битов: 0xE2 0x82 0xAC.

Примечание: этобыло бы возможно закодировать это также как четырехоктетную последовательность, расширяя ноль кодовой точки еще дальше.Это называется избыточным кодированием и не допускается спецификацией UTF-8.Кодировки должны быть как можно короче.

Существует кодировка под названием Модифицированный UTF-8 , которая кодирует ASCII NUL не как ASCII, а как сверхдлинная многооктетная последовательность,Таким образом, строка MUTF-8 может содержать символы ASCII NUL без указания нулевого октета 0x00 и, таким образом, может обрабатываться средами, которые ожидают, что строки заканчиваются нулем.

0 голосов
/ 11 марта 2019

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

Первый вопрос касался "é"который дает "\xc3\xa9" при кодировании с utf8 и где ord("é") возвращает 233.Ясно, что 233 не было суммой 195 (десятичное представление c3) и 169 (то же самое для a9).Так что же происходит?

"é" имеет соответствующую точку Unicode U+00E9.Десятичное значение для шестнадцатеричного числа e9 равно 233. Так вот что такое ord("é").

Так как же это закончится как "\xc3\xa9"?

As Jörg W Mittagобъяснено и продемонстрировано, что в utf8 все не-ASCII "закодированы как многооктетная последовательность" .

Двоичное представление 233 равно 11101001.Поскольку это не ASCII, его необходимо упаковать в двухоктетную последовательность, которая в соответствии с Йоргом будет следовать этому шаблону:

110xxxxx 10xxxxxx (110 и 10 фиксированы, оставляя место для пяти битов в первом октетеи шесть бит во втором - всего 11).

Таким образом, 8-битное двоичное представление 233 вставляется в этот шаблон, заменяя xx-части ... Так как доступно 11 битов, и нам нужно только 8 битов, мы дополняем 8 битов еще 3, 000, (т.е. 00011101001).

^^^00011 ^^101001 (000, за которым следует наше 8-битное представление 233)

11000011 10101001 (двоичное представление 233, вставленное впоследовательность октетов)

11000011 равно гексу c3, поскольку 10101001 равно a9, что другими словами соответствует исходной последовательности "\xc3\xa9"

Аналогичное пошаговое руководство длясимвол "Ĭ":

'Ĭ'.encode('utf-8') возвращает b'\xc4\xac'ord('Ĭ') равно 300.

Итак, снова точка Unicode для этого символа - U+012C, которая имеет десятичное значение 300 ((1 * 16 * 16) + (2 * 16 * 1) + (12 * 1)) - так что это орд-часть.

Опять двоичное представление 300 составляет 9 бит, 100101100.Итак, еще раз необходимо двухоктетную последовательность шаблона 110xxxxx 10xxxxxx.И снова мы дополняем его парой 0, поэтому достигаем 11 бит (00100101100).

^^^00100 ^^101100 (00, за которым следует наше 9-битное представление 300)

11000100 10101100 (двоичное представление 300, вставленное в две октетные последовательности).

11000100 соответствует c4 в шестнадцатеричном формате, 10101100 до ac - другими словами b'\xc4\xac'.

Спасибо всем за помощь в этом.Я многому научился.

0 голосов
/ 10 марта 2019

ASCII-кодировка "é" равна 0xe9, что равно 233 в десятичной базе.

Пример кода для вашего удобства:

for n in range(256):
    print(n,hex(n),chr(n))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...