fork download
  1. using System;
  2. using System.Text;
  3. using System.Globalization;
  4.  
  5. public class Test
  6. {
  7. public static void Main()
  8. {
  9. var myString = @"This is a string before an emoji:🔹This is after the emoji.";
  10. var teMyString = new StringInfo(myString);
  11. Console.WriteLine("TextElements Substring:");
  12. Console.WriteLine($"0-33:{teMyString.SubstringByTextElements(0, 33)}");
  13. Console.WriteLine($"0-34:{teMyString.SubstringByTextElements(0, 34)}");
  14. Console.WriteLine($"0-35:{teMyString.SubstringByTextElements(0, 35)}");
  15. Console.WriteLine("Custom Xanatos's substring:");
  16. Console.WriteLine($"0-33:{StringEx.UnicodeSafeSubstring(myString, 0, 33)}");
  17. Console.WriteLine($"0-34:{StringEx.UnicodeSafeSubstring(myString, 0, 34)}");
  18. Console.WriteLine($"0-35:{StringEx.UnicodeSafeSubstring(myString, 0, 35)}");
  19.  
  20. }
  21. }
  22. public static class StringEx
  23. {
  24. public static string UnicodeSafeSubstring(string str, int startIndex, int length)
  25. {
  26. if (str == null)
  27. {
  28. throw new ArgumentNullException("str");
  29. }
  30.  
  31. if (startIndex < 0 || startIndex > str.Length)
  32. {
  33. throw new ArgumentOutOfRangeException("startIndex");
  34. }
  35.  
  36. if (length < 0)
  37. {
  38. throw new ArgumentOutOfRangeException("length");
  39. }
  40.  
  41. if (startIndex + length > str.Length)
  42. {
  43. throw new ArgumentOutOfRangeException("length");
  44. }
  45.  
  46. if (length == 0)
  47. {
  48. return string.Empty;
  49. }
  50.  
  51. var sb = new StringBuilder(length);
  52.  
  53. int end = startIndex + length;
  54.  
  55. var enumerator = StringInfo.GetTextElementEnumerator(str, startIndex);
  56.  
  57. while (enumerator.MoveNext())
  58. {
  59. string grapheme = enumerator.GetTextElement();
  60. startIndex += grapheme.Length;
  61.  
  62. if (startIndex > length)
  63. {
  64. break;
  65. }
  66.  
  67. // Skip initial Low Surrogates/Combining Marks
  68. if (sb.Length == 0)
  69. {
  70. if (char.IsLowSurrogate(grapheme[0]))
  71. {
  72. continue;
  73. }
  74.  
  75. UnicodeCategory cat = char.GetUnicodeCategory(grapheme, 0);
  76.  
  77. if (cat == UnicodeCategory.NonSpacingMark || cat == UnicodeCategory.SpacingCombiningMark || cat == UnicodeCategory.EnclosingMark)
  78. {
  79. continue;
  80. }
  81. }
  82.  
  83. sb.Append(grapheme);
  84.  
  85. if (startIndex == length)
  86. {
  87. break;
  88. }
  89. }
  90.  
  91. return sb.ToString();
  92. }
  93. }
Success #stdin #stdout 0s 131648KB
stdin
Standard input is empty
stdout
TextElements Substring:
0-33:This is a string before an emoji:
0-34:This is a string before an emoji:🔹
0-35:This is a string before an emoji:🔹T
Custom Xanatos's substring:
0-33:This is a string before an emoji:
0-34:This is a string before an emoji:
0-35:This is a string before an emoji:🔹