Unicode SMP "персонаж" в C# char
Я пытаюсь определить последствия кодирования символов для программной системы, которую я планирую, и обнаружил что-то странное во время теста.
Насколько мне известно, C# внутренне использует UTF-16, который (насколько мне известно) охватывает каждую кодовую точку Unicode, используя два 16-битных поля. Поэтому я хотел сделать несколько литералов символов и намеренно выбрал и 얤, потому что первый из плоскости SMP, а второй из плоскости BMP. Результаты:
char ch1 = '얤'; // No problem
char ch2 = ''; // Compilation error "Too many characters in character literal"
В чем дело?
Следствием этого вопроса является то, что если у меня есть строка "얤얤", она правильно отображается в MessageBox, однако, когда я преобразую ее в char[] с помощью ToCharArray, я получаю массив с четырьмя элементами, а не с тремя. Также String.Length сообщается как четыре, а не три.
Я что-то здесь упускаю?
2 ответа
Ваш исходный файл не может быть сохранен в UTF-8 (что рекомендуется при использовании специальных символов в источнике), поэтому компилятор может фактически увидеть последовательность байтов, которая его смущает. Вы можете убедиться в этом, открыв исходный файл в шестнадцатеричном редакторе - байты, которые вы увидите вместо своего персонажа, скорее всего, будут другими.
Если он еще не включен, вы можете включить эту настройку в Сервис-> Параметры-> Документы в Visual Studio (я использую 2008) - опция Save documents as Unicode when data cannot be saved in codepage
,
Как правило, лучше указывать специальные символы, используя последовательность символов.
Эта статья MSDN описывает, как использовать \uxxxx
последовательности для указания нужного вам символа Unicode. В этой записи блога перечислены все различные escape-последовательности C# - причина, по которой я их включаю, в том, что в ней упоминается использование \xnnn - избегайте использования этого формата: это версия переменной длины \u
и это может вызвать проблемы в некоторых ситуациях (но не в вашей).
В статье MSDN указывается, почему назначение символов не подходит: кодовая точка для рассматриваемого символа -> FFFF, что находится за пределами диапазона для типа char.
Что касается строковой части вопроса, ответ состоит в том, что символ SMP представляется в виде двух значений символа. Этот вопрос SO включает в себя некоторый код, показывающий, как получить кодовые строки из строки, он включает использование StringInfo.GetTextElementEnumerator
Все это было описано в комментариях к этому ответу, поэтому я просто внес соответствующую информацию в этот ответ и теперь приму его.
MSDN говорит, что char
Тип может представлять Unicode 16-битный символ (таким образом, только символ формы BMP).
Если вы используете символ вне BMP (в UTF-16: дополнительная пара - 2x16 бит), компилятор обрабатывает его как два символа.