【问题标题】:Return code point of characters in C#在 C# 中返回字符的代码点
【发布时间】:2012-12-03 08:38:35
【问题描述】:

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

code point我的意思是实际的code point according to Unicode,它不同于code unit(UTF8有8位编码单元,UTF16有16-位代码单元,而 UTF32 有 32 位代码单元,在后一种情况下,在考虑字节顺序后,值等于代码点。

【问题讨论】:

  • 这个问题用词严重错误。 “返回一个字符的‘Unicode’”没有任何意义,坦率地说,是无稽之谈。您的示例清楚地表明了您真正想要的内容,但是需要重新修改标题。请这样做。
  • @tchrist,谢谢 .. 我更新了我的问题
  • 谢谢。我已向你投了赞成票以表示感谢。

标签: c# unicode unicode-string


【解决方案1】:

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

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

为了解决 cmets,C# 中的 char 是一个 16 位数字,并包含一个 UTF16 代码点。高于 16 位空间的代码点不能用 C# 字符表示。 C# 中的字符不是可变宽度。但是,string 可以有 2 个相互跟随的字符,每个字符都是一个代码单元,形成一个 UTF16 代码点。如果您有字符串输入和 16 位空间以上的字符,则可以使用 char.IsSurrogatePairChar.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);
}

【讨论】:

  • 它们是 unicode 代码单元,而不是代码点。需要多个代码单元的字符呢?
  • @driis... 与 GregS 评论相同
  • @driis:我没有对你投反对票,我只是提供一个澄清点。
  • @Qaesar 小写a ('a') 是U+0061,大写a ('A') 是U+0041
  • 对不起,如果我们让您感到困惑。问题是 Unicode 编码实际上有点复杂,尽管乍一看可能并不复杂。此答案中的代码或@dtb 发布的代码对您来说可以正常工作。如果你想要更多背景知识,我可以推荐joelonsoftware.com/articles/Unicode.html
【解决方案2】:

我在msdn forum 上找到了一个小方法。希望这会有所帮助。

    public int get_char_code(char character){ 
        UTF32Encoding encoding = new UTF32Encoding(); 
        byte[] bytes = encoding.GetBytes(character.ToString().ToCharArray()); 
        return BitConverter.ToInt32(bytes, 0); 
    } 

【讨论】:

  • 这是否会返回与(int)character 不同的内容?如果character 是代理对的一半会怎样?
  • @dtb(我知道答案很晚)。这段代码的有趣之处在于它使用UTF32Encoding 显示,但由于该方法只需要char,因此它没有任何效果,与(int) character 相同,但比强制转换慢得多。事实上,character.ToString().ToCharArray() 将始终返回一个包含一项(大小为 2 字节)的数组,而 BitConverter 永远不会返回大于 65535 的值。原则上不错的想法,但在呈现方式上毫无用处。
【解决方案3】:
public static string ToCodePointNotation(char c)
{

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

Console.WriteLine(ToCodePointNotation('a')); //U+0061

【讨论】:

  • @Qaesar 小写a ('a') 是U+0061,大写a ('A') 是U+0041
  • 如果Char.IsSurrogate(c),您应该抛出异常,因为这样的代码单元不能被视为代码点值,因此没有代码点符号。
  • 这个答案根本不正确,你不能假设 C# char 和 UTF-16 代码点之间存在一对一的映射,因为没有。
【解决方案4】:

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

【讨论】:

  • 不会转换为 UTF-32 而是将代码点作为整数返回,UTF-32 是一种编码,而不是整数。这种方法命名传播与微软将 UTF-16LE 编码标记为“unicode”相同的混淆
  • @Esailija:我不确定什么更令人困惑:使用名为 ConvertToUtf32 的方法转换为 Unicode 代码点,或转换为 UTF-32 并将结果视为 Unicode 代码点。到头来这可能会让人毛骨悚然。
  • 您不能将转换为实际 UTF-32 的结果视为代码点,您需要从编码中解码代码点,就像您从 UTF-16 或 UTF-8 解码一样,除了更简单。但我明白为什么这会被视为挑剔:P
【解决方案5】:

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]);
            }
        }
    }
}

【讨论】:

    【解决方案6】:

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

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

    【讨论】:

    • 作为一个改进点,而不是获取 utf8 字节然后将它们转换为 utf32,您可以首先获取 utf32 字节。
    • 另外,您提到的答案得分为负的原因是该方法仅接受 char 作为参数,这意味着它永远不会给您超过两个字节的信息。您的改进是巨大的,因为您实际上解析的是字符串而不是字符。
    • 谢谢@Chris。我简化了方法。
    【解决方案7】:

    在 .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
    

    【讨论】:

      猜你喜欢
      • 2021-04-10
      • 2020-07-24
      • 1970-01-01
      • 2017-11-30
      • 2016-03-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-20
      相关资源
      最近更新 更多