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 бит), компилятор обрабатывает его как два символа.

Другие вопросы по тегам