Вернуть кодовую точку символов в C#
Как я могу вернуть кодовую точку Unicode символа? Например, если вход "A", то выход должен быть "U+0041". В идеале решение должно заботиться о суррогатных парах.
Под кодовой точкой я подразумеваю фактическую кодовую точку в соответствии с Unicode, которая отличается от кодовой единицы (UTF8 имеет 8-битные кодовые единицы, UTF16 имеет 16-битные кодовые единицы, а UTF32 имеет 32-битные кодовые единицы, в последнем случае значение равно кодовой точке, после учета порядка байтов).
7 ответов
Легко, так как символы в C# на самом деле кодовые точки UTF16:
char x = 'A';
Console.WriteLine("U+{0:x4}", (int)x);
Чтобы ответить на комментарии, A char
в C# это 16-битное число и содержит кодовую точку UTF16. Кодовые точки выше 16 битового пространства не могут быть представлены символом C#. Символы в C# не переменной ширины. Строка, однако, может иметь 2 символа, следующих друг за другом, каждый из которых представляет собой единицу кода, образуя кодовую точку UTF16. Если у вас есть строковый ввод и символы выше 16-битного пространства, вы можете использовать char.IsSurrogatePair
а также Char.ConvertToUtf32
, как предлагается в другом ответе:
string input = ....
for(int i = 0 ; i < input.Length ; i += Char.IsSurrogatePair(input,i) ? 2 : 1)
{
int x = Char.ConvertToUtf32(input, i);
Console.WriteLine("U+{0:X4}", x);
}
Следующий код записывает кодовые точки string
вход в консоль:
string input = "\uD834\uDD61";
for (var i = 0; i < input.Length; i += char.IsSurrogatePair(input, i) ? 2 : 1)
{
var codepoint = char.ConvertToUtf32(input, i);
Console.WriteLine("U+{0:X4}", codepoint);
}
Выход:
U + 1D161
Поскольку строки в.NET имеют кодировку UTF-16, char
значения, которые составляют строку, должны быть сначала преобразованы в UTF-32.
В .NET Core 3.0 или более поздней версии вы можете использовать Rune Struct:
// Note that and are encoded using surrogate pairs
// but A, B, C and ✋ are not
var runes = "ABC✋".EnumerateRunes();
foreach (var r in runes)
Console.Write($"U+{r.Value:X4} ");
// Writes: U+0041 U+0042 U+0043 U+270B U+1F609 U+1F44D
C# не может хранить кодовые точки Unicode в char
, как char
только 2 байта и кодовые точки Unicode обычно превышают эту длину. Решение состоит в том, чтобы либо представить кодовую точку в виде последовательности байтов (либо в виде байтового массива, либо "сведенного" в 32-битный примитив), либо в виде строки. Принятый ответ конвертируется в UTF32, но это не всегда идеально.
Это код, который мы используем для разделения строки на ее компоненты кодовой точки Unicode, но сохраняя собственную кодировку UTF-16. Результатом является перечисляемый объект, который можно использовать для собственного сравнения (под) строк в C#/.NET:
public class InvalidEncodingException : System.Exception
{ }
public static IEnumerable<string> UnicodeCodepoints(this string s)
{
for (int i = 0; i < s.Length; ++i)
{
if (Char.IsSurrogate(s[i]))
{
if (s.Length < i + 2)
{
throw new InvalidEncodingException();
}
yield return string.Format("{0}{1}", s[i], s[++i]);
}
else
{
yield return string.Format("{0}", s[i]);
}
}
}
}
На самом деле, в ответе @Yogendra Singh есть некоторая заслуга, в настоящее время единственная с отрицательным голосованием. Работу можно сделать так
public static IEnumerable<int> Utf8ToCodePoints(this string s)
{
var utf32Bytes = Encoding.UTF32.GetBytes(s);
var bytesPerCharInUtf32 = 4;
Debug.Assert(utf32bytes.Length % bytesPerCharInUtf32 == 0);
for (int i = 0; i < utf32bytes.Length; i+= bytesPerCharInUtf32)
{
yield return BitConverter.ToInt32(utf32bytes, i);
}
}
Протестировано с
var surrogatePairInput = "abc";
Debug.Assert(surrogatePairInput.Length == 5);
var pointsAsString = string.Join(";" ,
surrogatePairInput
.Utf8ToCodePoints()
.Select(p => $"U+{p:X4}"));
Debug.Assert(pointsAsString == "U+0061;U+0062;U+0063;U+1F4A9");
Пример уместен, потому что куча пу представлена в виде суррогатной пары.
public static string ToCodePointNotation(char c)
{
return "U+" + ((int)c).ToString("X4");
}
Console.WriteLine(ToCodePointNotation('a')); //U+0061
Я нашел небольшой метод на форуме MSDN. Надеюсь это поможет.
public int get_char_code(char character){
UTF32Encoding encoding = new UTF32Encoding();
byte[] bytes = encoding.GetBytes(character.ToString().ToCharArray());
return BitConverter.ToInt32(bytes, 0);
}