diff options
| author | Luke Pulverenti <luke.pulverenti@gmail.com> | 2013-12-08 15:47:11 -0500 |
|---|---|---|
| committer | Luke Pulverenti <luke.pulverenti@gmail.com> | 2013-12-08 15:47:11 -0500 |
| commit | 803d60d9cff49bad9e6a53d43c2a39cc5dffb2dc (patch) | |
| tree | 59286ed94cff760d8b376e9b2ba42a6950d00581 /MediaBrowser.Server.Implementations/Sorting/AlphanumComparator.cs | |
| parent | 96961572cd592153eb03c44a315e6ed4e421da5b (diff) | |
support natural sorting
Diffstat (limited to 'MediaBrowser.Server.Implementations/Sorting/AlphanumComparator.cs')
| -rw-r--r-- | MediaBrowser.Server.Implementations/Sorting/AlphanumComparator.cs | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/MediaBrowser.Server.Implementations/Sorting/AlphanumComparator.cs b/MediaBrowser.Server.Implementations/Sorting/AlphanumComparator.cs new file mode 100644 index 000000000..2ced9a566 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Sorting/AlphanumComparator.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace MediaBrowser.Server.Implementations.Sorting +{ + public class AlphanumComparator : IComparer<string> + { + 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); + } + } +} |
