22

如何返回字符的Unicode 代码点?例如,如果输入是“A”,那么输出应该是“U+0041”。理想情况下,解决方案应该处理代理对

代码点是指根据Unicode的实际代码点,它不同于代码单元(UTF8 有 8 位代码单元,UTF16 有 16 位代码单元,UTF32 有 32 位代码单元,在后一种情况下,值等于代码点,在考虑了字节序之后)。

4

7 回答 7

13

以下代码将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。

于 2012-12-15T16:46:27.530 回答
11

很简单,因为 C# 中的字符实际上是 UTF16 代码点:

char x = 'A';
Console.WriteLine("U+{0:x4}", (int)x);

为了解决这些注释,charC# 中的 A 是一个 16 位数字,并包含一个 UTF16 代码点。高于 16 位空间的代码点不能用 C# 字符表示。C# 中的字符不是可变宽度。然而,一个字符串可以有 2 个字符,每个字符都是一个代码单元,形成一个 UTF16 代码点。如果您有字符串输入和 16 位空间以上的字符,则可以使用char.IsSurrogatePairand 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);
}
于 2012-12-15T16:33:33.800 回答
4

C# 不能将 unicode 代码点存储在 a 中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]);
            }
        }
    }
}
于 2017-04-07T14:14:24.187 回答
3

在 .NET Core 3.0 或更高版本中,您可以使用Rune Struct

// Note that  and  are encoded using surrogate pairs
// but A, B, C and ✋ are not
var runes = "ABC✋&quot;.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
于 2021-03-05T18:32:50.470 回答
2

实际上@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");

示例是相关的,因为一堆便便表示为代理对。

于 2017-06-21T15:12:26.630 回答
-1

我在msdn 论坛上找到了一个小方法。希望这可以帮助。

    public int get_char_code(char character){ 
        UTF32Encoding encoding = new UTF32Encoding(); 
        byte[] bytes = encoding.GetBytes(character.ToString().ToCharArray()); 
        return BitConverter.ToInt32(bytes, 0); 
    } 
于 2012-12-15T16:39:51.797 回答
-1
public static string ToCodePointNotation(char c)
{

    return "U+" + ((int)c).ToString("X4");
}

Console.WriteLine(ToCodePointNotation('a')); //U+0061
于 2012-12-15T16:46:13.080 回答