c# - 将 Unicode 代理项对转换为文字字符串

标签 c# .net unicode unicode-escapes

我正在尝试将一个高位 Unicode 字符从一个字符串读入另一个字符串。为简洁起见,我将简化我的代码,如下所示:

public static void UnicodeTest()
{
    var highUnicodeChar = "𝐀"; //Not the standard A

    var result1 = highUnicodeChar; //this works
    var result2 = highUnicodeChar[0].ToString(); // returns \ud835
}

当我将 highUnicodeChar 直接分配给 result1 时,它保留了 𝐀 的字面值。当我尝试通过索引访问它时,它返回 \ud835。据我了解,这是一对用于表示 UTF-32 字符的 UTF-16 字符代理项。我很确定这个问题与尝试将 char 隐式转换为 string 有关。

最后,我希望 result2 产生与 result1 相同的值。我该怎么做?

最佳答案

Unicode , 你有 code points .这些是 21 位长。你的角色𝐀,Mathematical Bold Capital A , 代码点为 U+1D400。

在 Unicode 编码中,您有代码单元。这些是编码的自然单位:8-bit对于 UTF-8 , 16-bit对于 UTF-16 , 等等。一个或多个代码单元编码单个代码点。

在 UTF-16 中,构成单个代码点的两个代码单元称为代理对。代理对用于编码大于 16 位的任何代码点,即 U+10000 及以上。

这在 .NET 中有点棘手,因为 .NET Char 表示单个 UTF-16 代码单元,而 .NET String 是代码的集合单位。

所以你的代码点 𝐀 (U+1D400) 不能放在 16 位中,需要一个代理对,这意味着你的字符串中有两个代码单元:

var highUnicodeChar = "𝐀";
char a = highUnicodeChar[0]; // code unit 0xD835
char b = highUnicodeChar[1]; // code unit 0xDC00

这意味着当您像那样索引字符串时,您实际上只会得到代理项对的一半。

您可以使用 IsSurrogatePair测试代理对。例如:

string GetFullCodePointAtIndex(string s, int idx) =>
    s.Substring(idx, char.IsSurrogatePair(s, idx) ? 2 : 1);

重要的是要注意 Unicode 中变量编码的兔子洞并没有在代码点结束。 字素簇 是大多数人在被问到时最终会称之为“字符”的“可见事物”。一个字素簇由一个或多个代码点组成:一个基本字符和零个或多个组合字符。组合字符的一个示例是元音变音符或您可能想要添加的各种其他装饰/修饰符。参见 this answer有关组合字符可以做什么的可怕示例。

要测试组合字符,您可以使用 GetUnicodeCategory检查封闭标记、非间距标记或间距标记。

关于c# - 将 Unicode 代理项对转换为文字字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52584308/

相关文章:

c# - 垃圾收集器的替代品是什么?

vim - 如何让 vim 正确呈现阿拉伯文本?

c# - 如何获取程序集的完整文件路径?

c# - ASP.Net:回发后如何维护文本框状态

c# - 回调的概念 (C#)

c# - 如何刷新绑定(bind)源

c# - 哪些现有的 CLR 主机不提供托管和非托管线程之间的一对一映射?

unicode - UTF-8编码为什么前缀10?

javascript - Unicode:如何获取字符的所有代码点,例如ã(所以它可以在 JavaScript 正则表达式中使用)?

c# - ServicePointManager 监控 HTTP 请求