Что такое кодировка символов и почему я должен беспокоиться об этом
Я совершенно запутался в концепции кодировки символов.
Что такое Юникод, ГБК и т. Д.? Как язык программирования использует их?
Нужно ли мне знать о них? Есть ли более простой или быстрый способ программирования, не беспокоясь о них?
3 ответа
(Обратите внимание, что я использую некоторые из этих терминов свободно / разговорно для более простого объяснения, которое все еще затрагивает ключевые моменты.)
Байт может иметь только 256 различных значений, составляющих 8 бит.
Поскольку существуют наборы символов с более чем 256 символами в наборе символов, в общем, нельзя просто сказать, что каждый символ является байтом.
Следовательно, должны быть сопоставления, описывающие, как превратить каждый символ в наборе символов в последовательность байтов. Некоторые символы могут быть сопоставлены с одним байтом, но другие должны быть сопоставлены с несколькими байтами.
Эти отображения являются кодировками, потому что они говорят вам, как кодировать символы в последовательности байтов.
Что касается Unicode, на очень высоком уровне Unicode - это попытка назначить один уникальный номер каждому персонажу. Очевидно, что это число должно быть чем-то шире байта, поскольку в нем более 256 символов:) Java использует версию Unicode, в которой каждому символу присваивается 16-битное значение (и именно поэтому символы Java имеют 16-битную ширину и целое число значения от 0 до 65535). Когда вы получаете байтовое представление символа Java, вы должны сообщить JVM кодировку, которую вы хотите использовать, чтобы она знала, как выбрать последовательность байтов для символа.
ASCII является фундаментальным
Первоначально 1 символ всегда хранился как 1 байт. Байт (8 бит) имеет потенциал для различения 256 возможных значений. Но на самом деле были использованы только первые 7 бит. Таким образом, только 128 символов были определены. Этот набор известен как набор символов ASCII.
0x00
-0x1F
содержат коды рулевого управления (например, CR, LF, STX, ETX, EOT, BEL,...)0x20
-0x40
содержать цифры и знаки препинания0x41
-0x7F
содержат в основном буквенные символы0x80
-0xFF
8-й бит = не определено.
Французский, немецкий и многие другие языки нуждались в дополнительных символах. (например à, é, ç, ô, ...
), которые не были доступны в наборе символов ASCII. Поэтому они использовали 8-й бит для определения своих персонажей. Это то, что известно как " расширенный ASCII ".
Проблема в том, что дополнительный 1 бит не обладает достаточной емкостью, чтобы охватить все языки мира. Таким образом, каждый регион имеет свой вариант ASCII. Есть много расширенных кодировок ASCII (latin-1
будучи очень популярным).
Популярный вопрос: "Является ли ASCII набор символов или это кодировка"? ASCII
это набор символов Однако в программировании charset
а также encoding
дико используются как синонимы. Если я хочу обратиться к кодировке, которая содержит только символы ASCII и ничего более (8-й бит всегда равен 0): это US-ASCII
,
Юникод идет на шаг вперед
Юникод также является набором символов (не кодировка). Он использует те же символы, что и стандарт ASCII, но расширяет список дополнительными символами, что дает каждому символу кодовую точку в формате u+xxxx
, Он имеет амбиции содержать всех персонажей (и популярные значки), используемых во всем мире.
UTF-8, UTF-16 и UTF-32 - это кодировки, которые применяют таблицу символов Unicode. Но у каждого из них есть свой способ кодирования. UTF-8 будет использовать только 1 байт при кодировании символа ASCII, давая тот же вывод, что и любое другое кодирование ASCII. Но для других символов он будет использовать первый бит, чтобы указать, что последует второй байт.
GBK - это кодировка, которая, как и UTF-8, использует несколько байтов. Принцип почти такой же. Первый байт соответствует стандарту ASCII, поэтому используются только 7 бит. Но, как и в UTF-8, 8-й бит можно использовать для указания наличия 2-го байта, который он затем использует для кодирования одного из 22 000 китайских символов. Основное отличие состоит в том, что это не соответствует набору символов Unicode, напротив, он использует некоторый набор китайских символов.
Типы пантомимы
Типы MIME также часто путают с кодировками.
Не существует простого способа декодирования файла. Было бы идеально, если бы все файлы содержали префикс для указания того, в какой кодировке были сохранены их данные. В конце концов, приложение (или его разработчик) определяет кодировку (например, US-ASCII
, UTF-8
, некоторые системные по умолчанию...).
При отправке данных через Интернет такая же проблема существует. К счастью, некоторые протоколы, такие как HTTP, используют объявления типов MIME, чтобы указать, какие данные и набор символов используются этими данными. Типичный заголовок HTTP содержит это:
Content-Type: text/html; charset=utf-8
Но для text/xml
это было бы бессмысленно (параметр charset будет даже игнорироваться). XML-парсеры в общем случае будут читать первую строку файла в поисках <?xml encoding=...
тег. Если он там, то они снова откроют файл, используя эту кодировку.
Та же проблема существует при отправке электронных писем. Электронное письмо может содержать HTML-сообщение или просто текст.
Ярлыки
В случае Java (и многих других языков программирования) в дополнение к опасностям кодирования существует также сложность приведения байтов и целых чисел к символам, поскольку их содержимое хранится в разных диапазонах.
- байт хранится как подписанный байт (диапазон:
-128
в127
). -
char
Тип в Java хранится в 2 байтах без знака (диапазон:0
-65535
) - поток возвращает целое число в диапазоне
-1
в255
,
Если вы знаете, что ваши данные содержат только значения ASCII. Затем, используя соответствующий навык, вы можете анализировать данные из байтов в символы или сразу же переносить их в строки.
// the -1 indicates that there is no data
int input = stream.read();
if (input == -1) throw new EOFException();
// bytes must be made positive first.
byte myByte = (byte) input;
int unsignedInteger = myByte & 0xFF;
char ascii = (char)(unsignedInteger);
Ярлык в java - использовать читателей и писателей и указывать кодировку при их создании.
// wrap your stream in a reader.
// specify the encoding
// The reader will decode the data for you
Reader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
Как объяснялось ранее для файлов XML, это не имеет большого значения, потому что любой приличный маршаллер DOM или JAXB будет проверять наличие атрибута кодировки.
обсуждение
В ответ на обсуждение в разделе комментариев приведен дополнительный чертеж, иллюстрирующий разницу между кодировкой и набором символов.
Вот крайний пример, который иллюстрирует, что набор символов - это просто примитивное отображение, в то время как кодировка больше похожа на алгоритм, который диктует, как символы должны переводиться в байты. Пожалуйста, обратите внимание, что "Сумасшедшая кодировка" использует внутренний набор "Сумасшедший набор символов".
Это отношение точно так же, как отношение UTF-8 к юникоду. Unicode - это просто набор символов, но это UTF-8, который определяет, как этот набор символов должен быть переведен в байты. Similary UTF-16 также использует Unicode, но переводит его совершенно по-другому. UTF-8 и UTF-16 - это кодировки, основанные на наборе символов Unicode.
Кодировка символов - это то, что вы используете для решения проблемы написания программного обеспечения для тех, кто использует другой язык, чем вы.
Вы не знаете, каковы персонажи и как они упорядочены. Следовательно, вы не знаете, как будут выглядеть строки в этом новом языке в двоичном формате, и, честно говоря, вам все равно.
То, что у вас есть, - это способ перевода строк с языка, на котором вы говорите, на язык, на котором они говорят (например, переводчик). Теперь вам нужна система, которая способна представлять оба языка в двоичном формате без конфликтов. Кодировка - это та система.
Это то, что позволяет вам писать программное обеспечение, которое работает независимо от того, как языки представлены в двоичном виде.
Большинство компьютерных программ должны общаться с человеком, используя текст на естественном языке (языке, используемом людьми). Но у компьютеров нет фундаментальных средств для представления текста: основное компьютерное представление представляет собой последовательность битов, организованных в байты и слова, с аппаратной поддержкой для интерпретации последовательностей битов как целых чисел фиксированной ширины с основанием 2 (двоичных) и вещественных чисел с плавающей запятой. Поэтому компьютерные программы должны иметь схему для представления текста в виде последовательности битов. По сути, это кодировка символов. Не существует очевидной или правильной схемы кодирования символов, поэтому существует множество возможных кодировок символов.
Однако у практических кодировок символов есть некоторые общие характеристики.
Закодированные тексты разбиты на последовательность знаков (графем).
Каждый из известных возможных символов имеет кодировку. Кодировка текста состоит из последовательности кодирования символов текста.
Каждому возможному (разрешенному) символу присваивается уникальное беззнаковое (неотрицательное) целое число (это иногда называется кодовой точкой). Поэтому тексты кодируются как последовательность целых чисел без знака. Различные кодировки символов отличаются допустимыми символами и тем, как они присваивают эти уникальные целые числа. Большинство кодировок символов не допускают использование всех символов многими системами письма (скриптами), которые существуют и существуют. Таким образом, кодировки символов различаются в зависимости от того, какие тексты они вообще могут представлять. Даже кодировки символов, которые могут представлять один и тот же текст, могут представлять его по-разному из-за различного назначения кодовых точек.
Целое число без знака, кодирующее символ, кодируется как последовательность битов. Кодировки символов различаются количеством битов, которые они используют для этого кодирования. Когда эти биты сгруппированы в байты (как в случае популярных кодировок), кодировки символов могут отличаться по порядку байтов. Кодировки символов могут различаться в зависимости от того, имеют ли они фиксированную ширину (одинаковое количество бит для каждого закодированного символа) или переменную ширину (с использованием большего количества бит для некоторых символов).
Следовательно, если компьютерная программа получает последовательность байтов, которые предназначены для представления некоторого текста, компьютерная программа должна знать кодировку символов, используемую для этого текста, если она должна выполнять какие-либо манипуляции с этим текстом (кроме как рассматривать его как непрозрачное значение и отправка его без изменений). Единственная возможность состоит в том, что текст сопровождается дополнительными данными, указывающими на используемую кодировку или программа требует (предполагает), что текст имеет определенную кодировку.
Точно так же, если компьютерная программа должна отправлять (выводить) текст в другую программу или устройство отображения, она должна либо сообщить адресату используемую кодировку символов, либо программа должна использовать кодировку, которую ожидает адресат.
На практике почти все проблемы с кодировкой символов возникают, когда адресат ожидает отправки текста с использованием одной кодировки символов, а текст фактически отправляется с другой кодировкой символов. Это, в свою очередь, обычно вызвано тем, что программист не принимает во внимание, что существует множество возможных кодировок символов и что их программа не может обрабатывать закодированный текст как непрозрачные значения, но должна преобразовывать из внешнего представления на входе и преобразовывать во внешнее представление на выходе.