using System; using System.Collections.Generic; using System.Text; namespace MediaBrowser.Server.Implementations.Sorting { public class AlphanumComparator : IComparer { private enum ChunkType { Alphanumeric, Numeric }; private static bool InChunk(char ch, char otherCh) { var type = ChunkType.Alphanumeric; if (char.IsDigit(otherCh)) { type = ChunkType.Numeric; } if ((type == ChunkType.Alphanumeric && char.IsDigit(ch)) || (type == ChunkType.Numeric && !char.IsDigit(ch))) { return false; } return true; } public static int CompareValues(string s1, string s2) { if (s1 == null || s2 == null) { return 0; } var thisMarker = 0; var thatMarker = 0; while ((thisMarker < s1.Length) || (thatMarker < s2.Length)) { if (thisMarker >= s1.Length) { return -1; } if (thatMarker >= s2.Length) { return 1; } var thisCh = s1[thisMarker]; var thatCh = s2[thatMarker]; var thisChunk = new StringBuilder(); var thatChunk = new StringBuilder(); while ((thisMarker < s1.Length) && (thisChunk.Length == 0 || InChunk(thisCh, thisChunk[0]))) { thisChunk.Append(thisCh); thisMarker++; if (thisMarker < s1.Length) { thisCh = s1[thisMarker]; } } while ((thatMarker < s2.Length) && (thatChunk.Length == 0 || InChunk(thatCh, thatChunk[0]))) { thatChunk.Append(thatCh); thatMarker++; if (thatMarker < s2.Length) { thatCh = s2[thatMarker]; } } int result = 0; // If both chunks contain numeric characters, sort them numerically if (char.IsDigit(thisChunk[0]) && char.IsDigit(thatChunk[0])) { var thisNumericChunk = Convert.ToInt32(thisChunk.ToString()); var thatNumericChunk = Convert.ToInt32(thatChunk.ToString()); if (thisNumericChunk < thatNumericChunk) { result = -1; } if (thisNumericChunk > thatNumericChunk) { result = 1; } } else { return string.Compare(thisChunk.ToString(), thatChunk.ToString(), StringComparison.CurrentCultureIgnoreCase); } if (result != 0) { return result; } } return 0; } public int Compare(string x, string y) { return CompareValues(x, y); } } }