Я бы начал с этого вопроса: что такое персонаж?
- Логическая идентификация: кодовая точка . Unicode назначает число каждому символу, которое не обязательно связано с какой-либо битовой / байтовой формой. Кодировки (например, UTF-8) определяют отображение в байтовые значения.
- Биты и байты: кодированная форма . Один или несколько байтов на кодовую точку, значения определяются используемой кодировкой.
- То, что вы видите на экране: графема . Графема создается из одной или нескольких кодовых точек. Это материал в конце презентации.
Этот код преобразует in.txt
из windows-1252
в UTF-8
и сохраняет его как out.txt
.
using System;
using System.IO;
using System.Text;
public class Enc {
public static void Main(String[] args) {
Encoding win1252 = Encoding.GetEncoding(1252);
Encoding utf8 = Encoding.UTF8;
using(StreamReader reader = new StreamReader("in.txt", win1252)) {
using(StreamWriter writer = new StreamWriter("out.txt", false, utf8)) {
char[] buffer = new char[1024];
while(reader.Peek() > 0) {
int r = reader.Read(buffer, 0, buffer.Length);
writer.Write(buffer, 0, r);
}
}
}
}
}
Здесь происходят две трансформации. Во-первых, байты декодируются с windows-1252
до UTF-16
(я думаю, с прямым порядком байтов) в буфер char
. Затем буфер преобразуется в UTF-8
.
* 1033 кодовые *
Некоторые примеры кодовых точек:
- U + 0041 - ПИСЬМО ЛАТИНСКОГО КАПИТАЛА (A)
- U + 00A3 - ЗВУКОВЫЙ ЗНАК (£)
- U + 042F - это ПИСЬМО КИРИЛЛИЧЕСКОГО КАПИТАЛА YA (& # x042F;)
- U + 1D50A - это МАТЕМАТИЧЕСКИЙ КАПИТАЛ FRAKTUR G (& # x1D50A;)
Кодировка
Где бы вы ни работали с персонажами, он будет в какой-то кодировке. C # использует UTF-16 для своего типа char , который он определяет как 16-битный.
Вы можете думать о кодировке как о табличном отображении между кодовыми точками и байтовыми представлениями.
CODEPOINT UTF-16BE UTF-8 WINDOWS-1252
U+0041 (A) 00 41 41 41
U+00A3 (£) 00 A3 C2 A3 A3
U+042F (Ya) 04 2F D0 AF -
U+1D50A D8 35 DD 0A F0 9D 94 8A -
Класс System.Text.Encoding предоставляет типы / методы для выполнения преобразований.
графемы
Графема, которую вы видите на экране, может состоять из нескольких кодов. Символ e-sharp (& # x0065; & # x0301;) может быть представлен двумя кодовыми точками: МАЛЕНЬКОЕ ЛАТИНСКОЕ ПИСЬМО E U + 0065 и КОМБИНИРОВАННЫЙ ОСТРЫЙ АКЦЕНТ U + 0301.
('& # x00E9;' чаще всего представляется одной кодовой точкой U + 00E9. Вы можете переключаться между ними с помощью нормализации. Однако не все последовательности объединения имеют одинаковый символьный эквивалент.)
Выводы
- Когда вы кодируете строку C # в кодировку, вы выполняете преобразование из UTF-16 в эту кодировку.
- Кодирование может быть преобразованием с потерями - большинство кодировок не в Юникоде может кодировать только подмножество существующих символов.
- Поскольку не все кодовые точки могут вписываться в один символ C #, число символов в строке может превышать количество кодовых точек, а количество кодовых точек может превышать количество отображаемых графем.
- «Длина» строки зависит от контекста, поэтому вам нужно знать, что вы применяете, и использовать соответствующий алгоритм. Как это обрабатывается, определяется используемым вами языком программирования.
- Присвоение одинаковым значениям символов Latin-1 во многих кодировках дает некоторым людям заблуждение ASCII.
(Это немного более многословно, чем я хотел, и, вероятно, больше, чем вы хотели, поэтому я остановлюсь. Я написал еще более многословный пост о кодировке Java здесь .)