C# 如何从UTF-16字符串中确定Unicode字符?

C# 如何从UTF-16字符串中确定Unicode字符?,c#,string,unicode,character-encoding,utf-16,C#,String,Unicode,Character Encoding,Utf 16,我有一个包含奇数Unicode空格字符的字符串,但我不确定这是什么字符。我知道在C#中,内存中的字符串是使用UTF-16格式编码的。确定字符串由哪些Unicode字符组成的好方法是什么 这个问题被标记为可能重复的问题 这不是这个问题的重复,因为我不是在问编码是什么。我已经知道C#中的字符串编码为UTF-16。我只是想用一种简单的方法来确定字符串中的Unicode值。BMP字符的长度最多为2个字节(值0x0000-0xffff),因此有很好的覆盖范围。这里有中文、泰文甚至蒙古文字母表中的字符,因此

我有一个包含奇数Unicode空格字符的字符串,但我不确定这是什么字符。我知道在C#中,内存中的字符串是使用UTF-16格式编码的。确定字符串由哪些Unicode字符组成的好方法是什么

这个问题被标记为可能重复的问题
这不是这个问题的重复,因为我不是在问编码是什么。我已经知道C#中的字符串编码为UTF-16。我只是想用一种简单的方法来确定字符串中的Unicode值。

BMP字符的长度最多为2个字节(值0x0000-0xffff),因此有很好的覆盖范围。这里有中文、泰文甚至蒙古文字母表中的字符,因此如果您不是编码专家,如果您的代码只处理BMP字符,您可能会被原谅。但同样,像这里这样的字符不会被假定为两个字节的代码正确处理。

Unicode似乎将字符识别为数字代码点。然而,并非所有的代码点实际上都指向字符,因为Unicode有字符的概念(我不太了解)。但是,每个Unicode字符串,甚至是一些无效的字符串(例如,组合字符的非法序列),都可以看作是代码点(数字)的列表

在UTF-16编码中,每个代码点被编码为2或4字节序列。在.net中,
Char
可能大致对应于2字节UTF-16序列或4字节UTF-16序列的一半。当
Char
包含4字节序列的一半时,它被视为“代理”,因为它仅在与另一个
Char
组合时才有意义,必须与另一个
Char
一起保存。要开始检查.net字符串,可以让.net告诉您字符串中包含的代码点,必要时自动将代理项对组合在一起。net提供了以下描述方式:

将字符串中指定位置的UTF-16编码字符或代理项对的值转换为Unicode代码点

声明针对以下情况引发
ArgumentException

指定的索引位置包含代理项对,并且该对中的第一个字符不是有效的高代理项,或者该对中的第二个字符不是有效的低代理项

因此,您可以在字符串中逐个字符地查找,并在和的帮助下找到所有Unicode代码点。当您没有遇到高代理时,当前字符适合一个
Char
,您只需要在字符串中前进一个
Char
。如果遇到高代理,则角色需要两个
Char
,并且需要前进两步:

static IEnumerable<int> GetCodePoints(string s)
{
    for (var i = 0; i < s.Length; i += char.IsHighSurrogate(s[i]) ? 2 : 1)
    {
        yield return char.ConvertToUtf32(s, i);
    }
}

另一个注意事项:根据您构建
String
实例的方式,它可能包含与代理项对相关的
Char
非法序列。对于此类字符串,
Char.ConvertToUtf32()
在遇到异常时将引发异常。但是,我认为
Encoding.GetString()
将始终返回有效字符串或引发异常。所以,一般来说,只要你的<代码>字符串实例来自“好”源,就不必担心<代码> char .CurnTutOff32()/Case>投掷(除非你在索引偏移的随机值中传递,因为你的偏移可能位于代理对的中间)。您是否担心可能是代理项对的字符?如果所有内容都在BMP中,您可以使用
foreach(文本中的字符c){Console.WriteLine((int)c);}
如果您不确定,可以使用char.ishighsrogate和char.IsLowSurrogate。BMP不表示哪种类型的字符?请尝试。请注意,快速观察表达式中的常规类别和命名块。svar.ToCharArray()是一种很好的方法,特别是当您将显示格式更改为十六进制时。仅使用BMP就可以摆脱的日子已经过去了一段时间。BMP以外的一类流行字符是表情符号☹️.
GetCodePoints(Encoding.UTF16.GetString(myUtf16Blob));