/// <summary> /// Reorder characters in the given range into their correct cannonical ordering with /// respect to combining class. /// </summary> /// <param name="buf">Buffer to reorder</param> private void CanonicalOrdering(StringBuilder buf) { int i, j; bool swap = false; int p_a, p_b; char t; int start = 0; int stop = buf.Length - 1; // From Unicode 3.0, section 3.10 // R1 For each character x in D, let p(x) be the combining class of x // R2 Wenever any pair (A, B) of adjacent characters in D is such that p(B)!=0 and // p(A)>p(B), exchange those characters // R3 Repeat step R2 until no exchanges can be made among any of the characters in D do { swap = false; p_a = Combining.Class(buf[start]); for (i = start; i < stop; i++) { p_b = Combining.Class(buf[i + 1]); if ((p_b != 0) && (p_a > p_b)) { for (j = i; j > 0; j--) { if (Combining.Class(buf[j]) <= p_b) { break; } t = buf[j + 1]; buf[j + 1] = buf[j]; buf[j] = t; swap = true; } /* We're re-entering the loop looking at the old * character again. Don't reset p_a.*/ continue; } p_a = p_b; // once we get to a start character without any swaps, // there can be no further changes. No sense constantly // rechecking stuff we've already checked. if (!swap && (p_a == 0)) { start = i; } } } while (swap); }
private void Comp(StringBuilder result) { // All decomposed and reordered. // Combine all combinable characters. int cc; int last_cc = 0; char c; int last_start = 0; for (int i = 0; i < result.Length; i++) { cc = Combining.Class(result[i]); if ((i > 0) && ((last_cc == 0) || (last_cc != cc)) && Compose.Combine(result[last_start], result[i], out c)) { result[last_start] = c; result.Remove(i, 1); i--; if (i == last_start) { last_cc = 0; } else { last_cc = Combining.Class(result[i - 1]); } continue; } if (cc == 0) { last_start = i; } last_cc = cc; } }