当前位置:  开发笔记 > 编程语言 > 正文

您如何从.NET字符串中获取一系列Unicode代码点?

如何解决《您如何从.NET字符串中获取一系列Unicode代码点?》经验,为你挑选了2个好方法。

我有一个字符范围限制列表,我需要检查字符串,但char.NET中的类型是UTF-16,因此一些字符变为古怪(代理)对.因此,当枚举a中的所有char's时string,我没有获得32位Unicode代码点,并且某些与高值的比较失败.

我非常了解Unicode,如果有必要,我可以自己解析字节,但我正在寻找一个C#/ .NET Framework BCL解决方案.所以......

如何将a转换为32位Unicode代码点string的数组(int[])?



1> Daniel A.A. ..:

你问的是代码点.在UTF-16(C#char)中,只有两种可能性:

    该字符来自Basic Multilingual Plane,由单个代码单元编码.

    该字符在BMP之外,并使用代理高低对代码单元进行编码

因此,假设字符串有效,则返回给定字符串的代码点数组:

public static int[] ToCodePoints(string str)
{
    if (str == null)
        throw new ArgumentNullException("str");

    var codePoints = new List(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();
}

代理对 and a composed character ñ:

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标准化时,它们被分解为一个符头,结合词干,组合旗帜和组合口音 - 断奏,所有代理对:

ToCodePoints("\U0001D162\U0001D181".Normalize());  // 
// { 0x1d158, 0x1d165, 0x1d170, 0x1d181 }          //    ?

请注意,leppie的解决方案不正确.问题是关于代码点,而不是文本元素.文本元素是代码点的组合,它们一起形成单个字素.例如,在上面的示例ñ中,字符串中的字符串由拉丁文小写字母表示,n后跟组合代字号??.Leppie的解决方案会丢弃任何无法归一化为单个代码点的组合字符.


@JeppeStigNielsen我改为添加了两个代码点的单个文本元素的示例,这两个代码点都是代理对,并在规范化下扩展为四个代码点代理对.

2> leppie..:

这个答案是不正确的.请参阅@ Virtlink的答案,了解正确答案.

static int[] ExtractScalars(string s)
{
  if (!s.IsNormalized())
  {
    s = s.Normalize();
  }

  List chars = new List((s.Length * 3) / 2);

  var ee = StringInfo.GetTextElementEnumerator(s);

  while (ee.MoveNext())
  {
    string e = ee.GetTextElement();
    chars.Add(char.ConvertToUtf32(e, 0));
  }

  return chars.ToArray();
}

注意:处理复合字符需要规范化.


▼:您的解决方案会丢弃所有修饰符字符,并且您正在处理_text elements_而不是_code points_.例如,`ExtractScalars("El Ni\u006E\u0303o")`转换回字符串的结果将是"El Nino"`而不是"ElNiño"`.
是的,我只是在调查那个.例如,梵文音节"ni"是一个可组合的字符"\ u0928\u093F",在规范化时不会变成一个代码点.此外,如果你有一个带有多个修饰符的拉丁字符(例如`^`和`~`),那么它也不会被标准化为单个代码点.你必须接受你的代码处理_text elements_(代表单个字母的代码点的组合)并且通过执行`ConvertToUtf32(e,0)`来丢弃除第一个以外的所有代码点.无法使用文本元素使代码与代码点一起使用.
推荐阅读
小色米虫_524
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有