Представьте себе сценарий, в котором Боб хочет отправить сообщение Алисе, но их компьютеры используют разные методы для представления букв. Компьютер Боба использует цифру 1 для обозначения буквы «А», а компьютер Алисы — цифру 2. Это несоответствие означает, что если Боб отправит Алисе сообщение «Привет, Алиса!», Компьютер Алисы не сможет его понять. Решение этой проблемы заключается в использовании стандарта кодировки символов. Стандарт кодировки символов — это способ представления букв, цифр и других символов в виде чисел. В этой статье будет объяснено кодирование символов с точки зрения трех основных понятий: ASCII, Unicode и UTF-8.
ASCII и кодовые точки
ASCII (Американский стандартный код обмена информацией) — один из самых ранних стандартов кодировки символов в истории вычислений. Разработанный в 1960-х годах, он использует 7 бит для представления символов, что дает 128 возможных комбинаций. Эти 128 кодовых точек соответствуют различным символам, включая буквы, цифры, знаки препинания и управляющие символы. Однако только 95 из этих кодовых точек представляют собой печатные символы, что ограничивает область применения ASCII. Основная идея ASCII заключалась в том, чтобы обеспечить общую основу для кодирования символов в ранних компьютерных системах.
В кодировке символов кодовая точка — это числовое значение, присвоенное определенному символу. В ASCII каждый символ соответствует определенной кодовой точке. Например, «H» представлен кодовой точкой 72, «E» — кодовой точкой 69 и так далее. Ограниченного набора символов ASCII было достаточно для первых компьютеров, но не для различных мировых систем письма.
Расцвет Юникода
По мере глобального распространения информационных технологий возникла необходимость в более комплексном стандарте кодирования символов. Это привело к разработке Unicode, стандарта кодирования текста, поддерживаемого Консорциумом Unicode. Юникод определяет большое количество кодовых точек, официально обозначаемых шестнадцатеричными числами, начинающимися с «U+». Например, кодовая точка Юникода для буквы «H» записывается как «U+0048». Юникод может представлять символы, сценарии и символы на самых разных языках, что делает его глобальным стандартом кодировки символов.
Кодовые страницы
Кодовая страница — это кодировка символов, которая связывает набор печатных символов и управляющих символов с уникальными числами. Каждое число обычно представляет собой двоичное значение в одном байте. Хотя ASCII и Unicode являются хорошо известными стандартами кодировки символов, кодовые страницы выступают в качестве посредников, устраняющих разрыв между этими стандартами и более старыми системами.
Кодовые страницы обеспечивают определенное сопоставление символов с числовыми значениями, что позволяет компьютерам правильно интерпретировать и отображать текст в пределах схем кодирования. По сути, кодовые страницы действуют как переводчики, гарантируя правильное отображение символов в системах, которые не полностью поддерживают Unicode.
Вот несколько часто используемых кодовых страниц:
Кодовая страница 1252 (Windows-1252):Эта кодовая страница, также известная как «Windows-1252» или «западноевропейская», широко используется для кодирования символов в дополнении Latin-1 и Latin-1. расширенные наборы символов A. Он включает символы, используемые во многих западноевропейских языках, таких как английский, французский, испанский и немецкий.
Кодовая страница 1250 (Windows-1250): Эта кодовая страница, известная как «Windows-1250» или «Центральноевропейская», используется для кодирования символов центральноевропейских и восточноевропейских языков, включая польский, чешский, венгерский и хорватский.
Кодовая страница 1254 (Windows-1254): «Windows-1254», также называемая «турецкой», используется для кодирования символов турецкого языка.
UTF-8: универсальное решение
Было предпринято несколько попыток решить проблему совместимости с Unicode, например UCS2 и UTF-16. Однако наиболее широко распространенным решением в последние годы является UTF-8, что означает 8-битный формат преобразования универсального набора символов.
Как работает UTF-8
UTF-8 (8-битный формат преобразования Unicode) — одна из наиболее широко используемых схем кодирования для представления символов Unicode. В UTF-8 используется подход кодирования переменной длины, который позволяет эффективно представлять символы из разных сценариев и языков, используя 1, 2, 3 или 4 байта.
Чтобы понять, как работает UTF-8, важно понять концепцию ведущих байтов и конечных битов. Кодировка символа в UTF-8 начинается с ведущего байта, который указывает количество байтов, используемых для этого символа. Количество старших битов, установленных в 1 в ведущем байте, говорит нам, сколько байтов следует за ним.
Например, для 2-байтового символа первый байт начинается с 110xxxxx
, где «x» представляет собой биты, полученные из кодовой точки символа. Завершающие байты начинаются с 10xxxxxx
, что указывает на то, что они содержат оставшиеся биты кодовой точки.
При кодировании символа в UTF-8:
- Для 1-байтового символа (от U+0000 до U+007F) используется один байт, в котором старший бит равен 0, за которым следуют 7 бит кодовой точки символа.
- Для 2-байтового символа (от U+0080 до U+07FF) используется начальный байт с
110xxxxx
и конечный байт с10xxxxxx
. - Для 3-байтового символа (от U+0800 до U+FFFF) используются три байта с
1110xxxx
,10xxxxxx
и10xxxxxx
. - Для 4-байтового символа (от U+10000 до U+10FFFF) используются четыре байта с
11110xxx
,10xxxxxx
,10xxxxxx
и10xxxxxx
.
В каждой последовательности «x» представляет биты, полученные из кодовой точки символа. Начальные байты (начинающиеся с «110», «1110» или «11110») указывают, сколько байтов используется для кодирования символа, а последующие байты (начинающиеся с «10») содержат фактические биты кода. точка.
Чтобы проиллюстрировать концепцию кодировки UTF-8, приведем фрагмент кода Python, который преобразует символы Юникода в соответствующие им представления UTF-8:
def unicode_to_utf8(char): # Check if the character is within the 1-byte Unicode range (U+0000 to U+007F) if 0x0000 <= char <= 0x007F: # 1-byte character: U+0000 to U+007F utf8_data = bytes([char]) # Check if the character is within the 2-byte Unicode range (U+0080 to U+07FF) elif 0x0080 <= char <= 0x07FF: # 2-byte character: U+0080 to U+07FF # Calculate the leading byte and trailing byte values leading_byte = 0xC0 | ((char >> 6) & 0x1F) # Leading byte starts with 110xxxxx trailing_byte = 0x80 | (char & 0x3F) # Trailing byte starts with 10xxxxxx # Combine the leading and trailing bytes utf8_data = bytes([leading_byte, trailing_byte]) # Check if the character is within the 3-byte Unicode range (U+0800 to U+FFFF) elif 0x0800 <= char <= 0xFFFF: # 3-byte character: U+0800 to U+FFFF # Calculate the leading bytes and trailing byte values leading_byte1 = 0xE0 | ((char >> 12) & 0x0F) # Leading byte 1 starts with 1110xxxx leading_byte2 = 0x80 | ((char >> 6) & 0x3F) # Leading byte 2 starts with 10xxxxxx trailing_byte = 0x80 | (char & 0x3F) # Trailing byte starts with 10xxxxxx # Combine the leading and trailing bytes utf8_data = bytes([leading_byte1, leading_byte2, trailing_byte]) # Check if the character is within the 4-byte Unicode range (U+10000 to U+10FFFF) elif 0x10000 <= char <= 0x10FFFF: # 4-byte character: U+10000 to U+10FFFF # Calculate the leading bytes and trailing byte values leading_byte1 = 0xF0 | ((char >> 18) & 0x07) # Leading byte 1 starts with 11110xxx leading_byte2 = 0x80 | ((char >> 12) & 0x3F) # Leading byte 2 starts with 10xxxxxx leading_byte3 = 0x80 | ((char >> 6) & 0x3F) # Leading byte 3 starts with 10xxxxxx trailing_byte = 0x80 | (char & 0x3F) # Trailing byte starts with 10xxxxxx # Combine the leading and trailing bytes utf8_data = bytes([leading_byte1, leading_byte2, leading_byte3, trailing_byte]) else: return None # Character is outside the valid Unicode range return utf8_data # Example: Convert Unicode characters to UTF-8 unicode_chars = [0x65, 0x03B1, 0x144c, 0x1f600] # Some sample Unicode characters for char in unicode_chars: utf8_data = unicode_to_utf8(char) if utf8_data: print(f"Unicode U+{char:04X} to UTF-8 Encoding: {utf8_data.hex()}") else: print(f"Character U+{char:04X} is outside the valid Unicode range.")
Предоставленный код преобразует символы Unicode в кодировку UTF-8, как показано в выводе ниже:
Unicode U+0065 to UTF-8 Encoding: 65 Unicode U+03B1 to UTF-8 Encoding: ceb1 Unicode U+144C to UTF-8 Encoding: e1918c Unicode U+1F600 to UTF-8 Encoding: f09f9880
Чтобы дополнительно проиллюстрировать концепцию кодировки UTF-8 и ее связь с Unicode, давайте рассмотрим 4-байтовый символ UTF-8.
На первом изображении ниже показан 4-байтовый символ UTF-8 «f09f9880» и соответствующее ему байтовое представление. Каждый байт представлен в шестнадцатеричном формате. В этом примере «f0», «9f», «98» и «80» — это четыре байта, составляющие кодировку символа UTF-8. Понимание того, как символы кодируются в байты, имеет основополагающее значение при работе с кодировкой символов в Python.
На втором изображении ниже показан символ Юникода «U+1F600» вместе с его байтовыми представлениями в UTF-8 и UTF-32.
- Представление UTF-8 «f09f9880» показывает, как этот символ кодируется с использованием UTF-8, где каждый байт имеет шестнадцатеричную форму.
- Представление UTF-32 «0001F600» отображает полное 32-битное представление кодовой точки Юникода для символа.