如何反转包含代理项对的字符串

我写过这个方法来反转一个字符串

public string Reverse(string s) { if(string.IsNullOrEmpty(s)) return s; TextElementEnumerator enumerator = StringInfo.GetTextElementEnumerator(s); var elements = new List(); while (enumerator.MoveNext()) { var cs = enumerator.GetTextElement().ToCharArray(); if (cs.Length > 1) { elements.AddRange(cs.Reverse()); } else { elements.AddRange(cs); } } elements.Reverse(); return string.Concat(elements); } 

现在,我不想开始讨论如何提高代码效率或者如何使用一个代替我的代码。 我知道你可以执行Xors和各种其他事情来改进这段代码。 如果我想稍后重构代码,我可以轻松地完成,因为我有unit testing。

目前,这正确地反转了BML字符串(包括带有像"Les Misérables" "Les Mise\u0301rables"这样的重音符号的字符串)和包含组合字符的字符串,例如"Les Mise\u0301rables"

我的测试包含代理对,如果它们表达如此

 Assert.AreEqual("𠈓", _stringOperations.Reverse("𠈓")); 

但如果我表达这样的代理人对

 Assert.AreEqual("\u10000", _stringOperations.Reverse("\u10000")); 

然后测试失败了。 是否有支持代理对的气密实施?

如果我在上面犯了任何错误,那么请指出这一点,因为我不是Unicode专家。

\u10000是一个由两个字符组成的字符串: က (Unicode代码点1000)后跟一个0 (可以通过检查方法中s的值来检测)。 如果您反转两个字符,它们将不再匹配输入。

看来你是在Unicode字符’LINEAR B SYLLABLE B008 A’(U + 10000)之后用hex代码点10000.从MSDN上的Unicode字符转义序列 :

\ uhexhexhex数字hex数字

\ Uhex数字hexhex数字hex数字hexhex数字hex数字hex数字

所以你必须使用四位或八位数。

使用\U00010000 (注意大写U)或\uD800\uDC00而不是\u10000

Necromancing。
发生这种情况是因为您使用List.Reverse而不是List.Reverse

 // using System.Globalization; TextElementEnumerator enumerator = StringInfo.GetTextElementEnumerator("Les Mise\u0301rables"); List elements = new List(); while (enumerator.MoveNext()) elements.Add(enumerator.GetTextElement()); elements.Reverse(); string reversed = string.Concat(elements); // selbarésiM seL 

有关更多信息,请参阅Jon Skeet的小马video: https : //vimeo.com/7403673

以下是如何正确反转字符串 (字符串,而不是字符序列 ):

 public static class Test { private static System.Collections.Generic.List GraphemeClusters(string s) { System.Collections.Generic.List ls = new System.Collections.Generic.List(); System.Globalization.TextElementEnumerator enumerator = System.Globalization.StringInfo.GetTextElementEnumerator(s); while (enumerator.MoveNext()) { ls.Add((string)enumerator.Current); } return ls; } // this private static string ReverseGraphemeClusters(string s) { if(string.IsNullOrEmpty(s) || s.Length == 1) return s; System.Collections.Generic.List ls = GraphemeClusters(s); ls.Reverse(); return string.Join("", ls.ToArray()); } public static void TestMe() { string s = "Les Mise\u0301rables"; string r = ReverseGraphemeClusters(s); // This would be wrong: // char[] a = s.ToCharArray(); // System.Array.Reverse(a); // string r = new string(a); System.Console.WriteLine(r); } } 

请注意,您需要知道它们之间的区别
– 一个角色和一个雕文
– 一个字节(8位)和一个码点/符文(32位)
– 一个代码点和一个GraphemeCluster [32+位](又名Grapheme / Glyph)

参考:

角色是一个超载的术语,可能意味着许多事情。

代码点是信息的primefaces单位。 文本是一系列代码点。 每个代码点都是一个由Unicode标准赋予的数字。

字素是一个或多个代码点的序列,它们显示为单个图形单元,读者将其识别为书写系统的单个元素。 例如,a和ä都是字形,但它们可能由多个代码点组成(例如,ä可能是两个代码点,一个用于基本字符a,后面跟一个用于diaresis;但也有一个替代的,遗留的,单个代码代表这个字形的点)。 某些代码点永远不会是任何字形的一部分(例如,零宽度非连接器或方向覆盖)。

字形是一种图像,通常以字体(字形集合)存储,用于表示字形或其部分。 字体可以将多个字形组合成单个表示,例如,如果上面的ä是单个代码点,则字体可以选择将其呈现为两个单独的,空间上重叠的字形。 对于OTF,字体的GSUB和GPOS表包含替换和定位信息以使其工作。 字体也可以包含同一字素的多个替代字形。

这是一个开始。 它可能不是最快的,但它似乎对我们所投入的东西起作用。

 internal static string ReverseItWithSurrogate(string stringToReverse) { string result = string.Empty; // We want to get the string into a character array first char[] stringArray = stringToReverse.ToCharArray(); // This is the object that will hold our reversed string. var sb = new StringBuilder(); bool haveSurrogate = false; // We are starting at the back and looking at each character. if it is a // low surrogate and the one prior is a high and not < 0, then we have a surrogate pair. for (int loopVariable = stringArray.Length - 1; loopVariable >= 0; loopVariable--) { // we cant' check the high surrogate if the low surrogate is index 0 if (loopVariable > 0) { haveSurrogate = false; if (char.IsLowSurrogate(stringArray[loopVariable]) && char.IsHighSurrogate(stringArray[loopVariable - 1])) { sb.Append(stringArray[loopVariable - 1]); sb.Append(stringArray[loopVariable]); // and force the second character to drop from our loop loopVariable--; haveSurrogate = true; } if (!haveSurrogate) { sb.Append(stringArray[loopVariable]); } } else { // Now we have to handle the first item in the list if it is not a high surrogate. if (!haveSurrogate) { sb.Append(stringArray[loopVariable]); } } } result = sb.ToString(); return result; } 

最好看不在Chrome中!

 using System.Linq; using System.Collections.Generic; using System; using System.Globalization; using System.Diagnostics; using System.Collections; namespace OrisNumbers { public static class IEnumeratorExtensions { public static IEnumerable AsIEnumerable(this IEnumerator iterator) { while (iterator.MoveNext()) { yield return (T)iterator.Current; } } } class Program { static void Main(string[] args) { var s = "foo 𝌆 bar mañana mañana" ; Debug.WriteLine(s); Debug.WriteLine(string.Join("", StringInfo.GetTextElementEnumerator(s.Normalize()).AsIEnumerable().Reverse())); Console.Read(); } } }