GraphemeHelper.cs 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
  1. using System.Globalization;
  2. namespace Terminal.Gui.Drawing;
  3. /// <summary>
  4. /// Provides utility methods for enumerating Unicode grapheme clusters (user-perceived characters)
  5. /// in a string. A grapheme cluster may consist of one or more <see cref="Rune"/> values,
  6. /// including combining marks or zero-width joiner (ZWJ) sequences such as emoji family groups.
  7. /// </summary>
  8. /// <remarks>
  9. /// <para>
  10. /// This helper uses <see cref="StringInfo.GetTextElementEnumerator(string)"/> to enumerate
  11. /// text elements according to the Unicode Standard Annex #29 (UAX #29) rules for
  12. /// extended grapheme clusters.
  13. /// </para>
  14. /// <para>
  15. /// On legacy Windows consoles (e.g., <c>cmd.exe</c>, <c>conhost.exe</c>), complex grapheme
  16. /// sequences such as ZWJ emoji or combining marks may not render correctly, even though
  17. /// the underlying string data is valid.
  18. /// </para>
  19. /// <para>
  20. /// For most accurate visual rendering, prefer modern terminals such as Windows Terminal
  21. /// or Linux-based terminals with full Unicode and font support.
  22. /// </para>
  23. /// </remarks>
  24. public static class GraphemeHelper
  25. {
  26. /// <summary>
  27. /// Enumerates extended grapheme clusters from a string.
  28. /// Handles surrogate pairs, combining marks, and basic ZWJ sequences.
  29. /// Safe for legacy consoles; memory representation is correct.
  30. /// </summary>
  31. public static IEnumerable<string> GetGraphemes (string text)
  32. {
  33. if (string.IsNullOrEmpty (text))
  34. {
  35. yield break;
  36. }
  37. TextElementEnumerator enumerator = StringInfo.GetTextElementEnumerator (text);
  38. while (enumerator.MoveNext ())
  39. {
  40. string element = enumerator.GetTextElement ();
  41. yield return element;
  42. }
  43. }
  44. }