【发布时间】:2012-12-30 03:29:43
【问题描述】:
我在 Jon Skeet 的博客上看到了 this post,他谈到了字符串反转。我想尝试他向自己展示的示例,但它似乎有效......这让我相信我不知道如何创建一个包含代理对的字符串,这实际上会导致字符串反转失败。实际上如何创建一个包含代理对的字符串,以便我自己看到失败?
【问题讨论】:
标签: c# string utf-16 utf-32 surrogate-pairs
我在 Jon Skeet 的博客上看到了 this post,他谈到了字符串反转。我想尝试他向自己展示的示例,但它似乎有效......这让我相信我不知道如何创建一个包含代理对的字符串,这实际上会导致字符串反转失败。实际上如何创建一个包含代理对的字符串,以便我自己看到失败?
【问题讨论】:
标签: c# string utf-16 utf-32 surrogate-pairs
术语“代理对”是指在UTF-16 编码方案中对具有高代码点的 Unicode 字符进行编码的方法(有关详细信息,请参阅this page);
在Unicode 字符编码中,字符映射到0x000000 和0x10FFFF 之间的值。在内部,UTF-16 编码方案用于存储 Unicode 文本字符串,其中考虑了两字节 (16-bit) 代码序列。由于两个字节只能包含从0x0000 到0xFFFF 的字符范围,因此会使用一些额外的复杂性来存储高于此范围(0x010000 到0x10FFFF)的值。
这是使用称为代理的代码点对完成的。代理字符分为两个不同的范围,称为 low surrogates 和 high 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 说得对……字符串和日期看起来很简单,但绝对不是。
【讨论】:
Int32 值:0x2A601 所以没有必要将Int32.Parse 与NumberStyles 一起使用。但是您也可以只说"\U0002A601" 来获取Unicode 字符。看我的回答。
string surrogate = "Les Misérables".Normalize(NormalizationForm.FormD);
最简单的方法是使用\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 软件是否正确处理了我的麻将字符。如果“有趣”字符不在这里,请尝试单击“编辑”对此答案并从文本中复制粘贴。)
【讨论】:
Char.IsSurrogate(myString[i]),并且能够正确识别代理对非常简单可靠的方法。