AlphanumComparator.cs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. using System.Collections.Generic;
  2. using System.Text;
  3. namespace MediaBrowser.Server.Implementations.Sorting
  4. {
  5. public class AlphanumComparator : IComparer<string>
  6. {
  7. private enum ChunkType { Alphanumeric, Numeric };
  8. private static bool InChunk(char ch, char otherCh)
  9. {
  10. var type = ChunkType.Alphanumeric;
  11. if (char.IsDigit(otherCh))
  12. {
  13. type = ChunkType.Numeric;
  14. }
  15. if ((type == ChunkType.Alphanumeric && char.IsDigit(ch))
  16. || (type == ChunkType.Numeric && !char.IsDigit(ch)))
  17. {
  18. return false;
  19. }
  20. return true;
  21. }
  22. public static int CompareValues(string s1, string s2)
  23. {
  24. if (s1 == null || s2 == null)
  25. {
  26. return 0;
  27. }
  28. int thisMarker = 0, thisNumericChunk = 0;
  29. int thatMarker = 0, thatNumericChunk = 0;
  30. while ((thisMarker < s1.Length) || (thatMarker < s2.Length))
  31. {
  32. if (thisMarker >= s1.Length)
  33. {
  34. return -1;
  35. }
  36. else if (thatMarker >= s2.Length)
  37. {
  38. return 1;
  39. }
  40. char thisCh = s1[thisMarker];
  41. char thatCh = s2[thatMarker];
  42. StringBuilder thisChunk = new StringBuilder();
  43. StringBuilder thatChunk = new StringBuilder();
  44. while ((thisMarker < s1.Length) && (thisChunk.Length == 0 || InChunk(thisCh, thisChunk[0])))
  45. {
  46. thisChunk.Append(thisCh);
  47. thisMarker++;
  48. if (thisMarker < s1.Length)
  49. {
  50. thisCh = s1[thisMarker];
  51. }
  52. }
  53. while ((thatMarker < s2.Length) && (thatChunk.Length == 0 || InChunk(thatCh, thatChunk[0])))
  54. {
  55. thatChunk.Append(thatCh);
  56. thatMarker++;
  57. if (thatMarker < s2.Length)
  58. {
  59. thatCh = s2[thatMarker];
  60. }
  61. }
  62. int result = 0;
  63. // If both chunks contain numeric characters, sort them numerically
  64. if (char.IsDigit(thisChunk[0]) && char.IsDigit(thatChunk[0]))
  65. {
  66. if (!int.TryParse(thisChunk.ToString(), out thisNumericChunk))
  67. {
  68. return 0;
  69. }
  70. if (!int.TryParse(thatChunk.ToString(), out thatNumericChunk))
  71. {
  72. return 0;
  73. }
  74. if (thisNumericChunk < thatNumericChunk)
  75. {
  76. result = -1;
  77. }
  78. if (thisNumericChunk > thatNumericChunk)
  79. {
  80. result = 1;
  81. }
  82. }
  83. else
  84. {
  85. result = thisChunk.ToString().CompareTo(thatChunk.ToString());
  86. }
  87. if (result != 0)
  88. {
  89. return result;
  90. }
  91. }
  92. return 0;
  93. }
  94. public int Compare(string x, string y)
  95. {
  96. return CompareValues(x, y);
  97. }
  98. }
  99. }