您在询问有关“代码点”的内容。在UTF-16(C#的
char
)中,只有两种可能性:
- 字符来自基本多文种平面,并由单个代码单元编码。
- 字符位于BMP之外,并使用代理高低对代码单元进行编码。
因此,假设字符串有效,这将返回给定字符串的代码
点数组:
public static int[] ToCodePoints(string str)
{
if (str == null)
throw new ArgumentNullException("str");
var codePoints = new List<int>(str.Length);
for (int i = 0; i < str.Length; i++)
{
codePoints.Add(Char.ConvertToUtf32(str, i));
if (Char.IsHighSurrogate(str[i]))
i += 1;
}
return codePoints.ToArray();
}
一个包含代理对
和组合字符ñ
的例子:
ToCodePoints("\U0001F300 El Ni\u006E\u0303o"); // El Niño
// { 0x1f300, 0x20, 0x45, 0x6c, 0x20, 0x4e, 0x69, 0x6e, 0x303, 0x6f } // E l N i n ̃◌ o
这是另一个例子。这两个代码点表示带有断音符号的32分音符,都是代理对:
ToCodePoints("\U0001D162\U0001D181"); //
// { 0x1d162, 0x1d181 } // ◌
当C-normalized时,它们被分解为一个音符头、组合茎、组合旗帜和组合重音-断音号,所有这些都是代理对:
ToCodePoints("\U0001D162\U0001D181".Normalize()); //
// { 0x1d158, 0x1d165, 0x1d170, 0x1d181 } // ◌
请注意,
leppie的解决方案是不正确的。这个问题涉及到
代码点而不是
文本元素。一个文本元素是由多个代码点组成的单个字形。例如,在上面的例子中,字符串中的
ñ
由拉丁小写字母
n
和一个组合波浪符
̃◌
表示。Leppie的解决方案会丢弃任何不能被规范化为单个代码点的组合字符。
var codePoint = Char.ConvertToUtf32(...); if(codePoint > 0xFFFF) i++;
而不是Char.IsHighSurrogate
。 - CodesInChaos0xFFFF
以上的码位,但如果我错了,请告诉我。 - Daniel A.A. Pelsmaekerñ
,可以通过(适当的)规范化变成一个代码点。 - Jeppe Stig Nielsen