【问题标题】:How do I create a string with a surrogate pair inside of it?如何创建一个包含代理对的字符串?
【发布时间】:2012-12-30 03:29:43
【问题描述】:

我在 Jon Skeet 的博客上看到了 this post,他谈到了字符串反转。我想尝试他向自己展示的示例,但它似乎有效......这让我相信我不知道如何创建一个包含代理对的字符串,这实际上会导致字符串反转失败。实际上如何创建一个包含代理对的字符串,以便我自己看到失败?

【问题讨论】:

    标签: c# string utf-16 utf-32 surrogate-pairs


    【解决方案1】:

    术语“代理对”是指在UTF-16 编码方案中对具有高代码点的 Unicode 字符进行编码的方法(有关详细信息,请参阅this page);

    Unicode 字符编码中,字符映射到0x0000000x10FFFF 之间的值。在内部,UTF-16 编码方案用于存储 Unicode 文本字符串,其中考虑了两字节 (16-bit) 代码序列。由于两个字节只能包含从0x00000xFFFF 的字符范围,因此会使用一些额外的复杂性来存储高于此范围(0x0100000x10FFFF)的值。

    这是使用称为代理的代码点对完成的。代理字符分为两个不同的范围,称为 low surrogateshigh surrogates,具体取决于它们是允许在两码序列的开头还是结尾。

    自己试试吧:

    String surrogate = "abc" + Char.ConvertFromUtf32(Int32.Parse("2A601", NumberStyles.HexNumber)) + "def";
    
    Char[] surrogateArray = surrogate.ToCharArray();
    Array.Reverse(surrogateArray);
    
    String surrogateReversed = new String(surrogateArray);
    

    或者这个,如果你想坚持博客示例:

    String surrogate = "Les Mise" + Char.ConvertFromUtf32(Int32.Parse("0301", NumberStyles.HexNumber)) + "rables";
    
    Char[] surrogateArray = surrogate.ToCharArray();
    Array.Reverse(surrogateArray);
    
    String surrogateReversed = new String(surrogateArray);
    

    nnd 然后使用调试器检查字符串值。 Jon Skeet 说得对……字符串和日期看起来很简单,但绝对不是。

    【讨论】:

    • 有趣的是,该示例完全按照 LinqPad 中的描述显示,但在 Visual Studio 控制台应用程序中却没有。
    • 在 C# 中,您可以像这样编写一个十六进制的Int32 值:0x2A601 所以没有必要将Int32.ParseNumberStyles 一起使用。但是您也可以只说"\U0002A601" 来获取Unicode 字符。看我的回答。
    • 关于《悲惨世界》,还有另一种分解方式:string surrogate = "Les Misérables".Normalize(NormalizationForm.FormD);
    【解决方案2】:

    最简单的方法是使用\U########,其中U 是大写字母,# 正好表示八个十六进制数字。如果值超过0000FFFF 十六进制,则需要代理对:

    string myString = "In the game of mahjong \U0001F01C denotes the Four of circles";
    

    您可以检查 myString.Length 以查看一个 Unicode 字符占用两个 .NET Char 值。请注意,char 类型有几个 static 方法可以帮助您确定 char 是否是代理对的一部分。

    如果您使用的 .NET 语言没有类似\U######## 转义序列,则可以使用方法ConvertFromUtf32,例如:

    string fourCircles = char.ConvertFromUtf32(0x1F01C);
    

    补充:如果您的 C# 源文件具有允许所有 Unicode 字符的编码,例如 UTF-8,您可以直接将字符放入文件中(通过复制粘贴)。例如:

    string myString = "In the game of mahjong ? denotes the Four of circles";
    

    该字符在源文件(在我的示例中)中采用 UTF-8 编码,但在应用程序运行且字符串在内存中时将采用 UTF-16 编码(代理对)。

    (不确定 Stack Overflow 软件是否正确处理了我的麻将字符。如果“有趣”字符不在这里,请尝试单击“编辑”对此答案并从文本中复制粘贴。)

    【讨论】:

    • Stack Overflow 软件正确处理您的麻将字符,我将复制粘贴到编辑器中,它显示 utf-8 序列 0xF0 0x9F 0x80 0x9C 这是一个 4 字节序列并编码 unicode 代码点 0x1F01C这是十进制的 127004,这确实是“麻将牌四圈”代码点。但可能(就像我一样)我们看不到字符,因为字体不包含字形,因此会显示替换字形/字符。
    • @brighty 是的,Stack Overflow 似乎可以完美地处理来自平面 0 外部的字符。问题可能是由于缺少字体或网络浏览器支持(旧浏览器)。
    • 感谢“有几个静态方法可以帮助您确定 char 是否是代理对的一部分”,我找到了Char.IsSurrogate(myString[i]),并且能够正确识别代理对非常简单可靠的方法。
    猜你喜欢
    • 2011-02-17
    • 2014-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多