Вернуть кодовую точку символов в 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); 
    } 
Другие вопросы по тегам