StringExtensions.cs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. using System;
  2. using System.Text.RegularExpressions;
  3. using ICU4N.Text;
  4. namespace Jellyfin.Extensions
  5. {
  6. /// <summary>
  7. /// Provides extensions methods for <see cref="string" />.
  8. /// </summary>
  9. public static partial class StringExtensions
  10. {
  11. private static readonly Lazy<string> _transliteratorId = new(() =>
  12. Environment.GetEnvironmentVariable("JELLYFIN_TRANSLITERATOR_ID")
  13. ?? "Any-Latin; Latin-Ascii; Lower; NFD; [:Nonspacing Mark:] Remove; [:Punctuation:] Remove;");
  14. private static readonly Lazy<Transliterator?> _transliterator = new(() =>
  15. {
  16. try
  17. {
  18. return Transliterator.GetInstance(_transliteratorId.Value);
  19. }
  20. catch (ArgumentException)
  21. {
  22. return null;
  23. }
  24. });
  25. // Matches non-conforming unicode chars
  26. // https://mnaoumov.wordpress.com/2014/06/14/stripping-invalid-characters-from-utf-16-strings/
  27. [GeneratedRegex("([\ud800-\udbff](?![\udc00-\udfff]))|((?<![\ud800-\udbff])[\udc00-\udfff])|(�)")]
  28. private static partial Regex NonConformingUnicodeRegex();
  29. /// <summary>
  30. /// Removes the diacritics character from the strings.
  31. /// </summary>
  32. /// <param name="text">The string to act on.</param>
  33. /// <returns>The string without diacritics character.</returns>
  34. public static string RemoveDiacritics(this string text)
  35. => Diacritics.Extensions.StringExtensions.RemoveDiacritics(
  36. NonConformingUnicodeRegex().Replace(text, string.Empty));
  37. /// <summary>
  38. /// Checks whether or not the specified string has diacritics in it.
  39. /// </summary>
  40. /// <param name="text">The string to check.</param>
  41. /// <returns>True if the string has diacritics, false otherwise.</returns>
  42. public static bool HasDiacritics(this string text)
  43. => Diacritics.Extensions.StringExtensions.HasDiacritics(text)
  44. || NonConformingUnicodeRegex().IsMatch(text);
  45. /// <summary>
  46. /// Counts the number of occurrences of [needle] in the string.
  47. /// </summary>
  48. /// <param name="value">The haystack to search in.</param>
  49. /// <param name="needle">The character to search for.</param>
  50. /// <returns>The number of occurrences of the [needle] character.</returns>
  51. public static int Count(this ReadOnlySpan<char> value, char needle)
  52. {
  53. var count = 0;
  54. var length = value.Length;
  55. for (var i = 0; i < length; i++)
  56. {
  57. if (value[i] == needle)
  58. {
  59. count++;
  60. }
  61. }
  62. return count;
  63. }
  64. /// <summary>
  65. /// Returns the part on the left of the <c>needle</c>.
  66. /// </summary>
  67. /// <param name="haystack">The string to seek.</param>
  68. /// <param name="needle">The needle to find.</param>
  69. /// <returns>The part left of the <paramref name="needle" />.</returns>
  70. public static ReadOnlySpan<char> LeftPart(this ReadOnlySpan<char> haystack, char needle)
  71. {
  72. if (haystack.IsEmpty)
  73. {
  74. return ReadOnlySpan<char>.Empty;
  75. }
  76. var pos = haystack.IndexOf(needle);
  77. return pos == -1 ? haystack : haystack[..pos];
  78. }
  79. /// <summary>
  80. /// Returns the part on the right of the <c>needle</c>.
  81. /// </summary>
  82. /// <param name="haystack">The string to seek.</param>
  83. /// <param name="needle">The needle to find.</param>
  84. /// <returns>The part right of the <paramref name="needle" />.</returns>
  85. public static ReadOnlySpan<char> RightPart(this ReadOnlySpan<char> haystack, char needle)
  86. {
  87. if (haystack.IsEmpty)
  88. {
  89. return ReadOnlySpan<char>.Empty;
  90. }
  91. var pos = haystack.LastIndexOf(needle);
  92. if (pos == -1)
  93. {
  94. return haystack;
  95. }
  96. if (pos == haystack.Length - 1)
  97. {
  98. return ReadOnlySpan<char>.Empty;
  99. }
  100. return haystack[(pos + 1)..];
  101. }
  102. /// <summary>
  103. /// Returns a transliterated string which only contain ascii characters.
  104. /// </summary>
  105. /// <param name="text">The string to act on.</param>
  106. /// <returns>The transliterated string.</returns>
  107. public static string Transliterated(this string text)
  108. {
  109. return (_transliterator.Value is null) ? text : _transliterator.Value.Transliterate(text);
  110. }
  111. }
  112. }