From 803d60d9cff49bad9e6a53d43c2a39cc5dffb2dc Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 8 Dec 2013 15:47:11 -0500 Subject: support natural sorting --- .../Sorting/AlphanumComparator.cs | 113 +++++++++++++++++++++ .../Sorting/SortNameComparer.cs | 3 +- 2 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 MediaBrowser.Server.Implementations/Sorting/AlphanumComparator.cs (limited to 'MediaBrowser.Server.Implementations/Sorting') 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 + { + 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); + } + } +} diff --git a/MediaBrowser.Server.Implementations/Sorting/SortNameComparer.cs b/MediaBrowser.Server.Implementations/Sorting/SortNameComparer.cs index 873753a2b..e635cfbe5 100644 --- a/MediaBrowser.Server.Implementations/Sorting/SortNameComparer.cs +++ b/MediaBrowser.Server.Implementations/Sorting/SortNameComparer.cs @@ -1,7 +1,6 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Sorting; using MediaBrowser.Model.Querying; -using System; namespace MediaBrowser.Server.Implementations.Sorting { @@ -18,7 +17,7 @@ namespace MediaBrowser.Server.Implementations.Sorting /// System.Int32. public int Compare(BaseItem x, BaseItem y) { - return string.Compare(x.SortName, y.SortName, StringComparison.CurrentCultureIgnoreCase); + return AlphanumComparator.CompareValues(x.SortName, y.SortName); } /// -- cgit v1.2.3 From 91b5a8101f60efd824b2111b52955208fb705e08 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 8 Dec 2013 16:31:14 -0500 Subject: improve episode sorting --- .../Sorting/AiredEpisodeOrderComparer.cs | 11 ++++++++++- MediaBrowser.Server.Implementations/Sorting/NameComparer.cs | 3 +-- .../Sorting/SeriesSortNameComparer.cs | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-) (limited to 'MediaBrowser.Server.Implementations/Sorting') diff --git a/MediaBrowser.Server.Implementations/Sorting/AiredEpisodeOrderComparer.cs b/MediaBrowser.Server.Implementations/Sorting/AiredEpisodeOrderComparer.cs index 76971342a..d6b78bd84 100644 --- a/MediaBrowser.Server.Implementations/Sorting/AiredEpisodeOrderComparer.cs +++ b/MediaBrowser.Server.Implementations/Sorting/AiredEpisodeOrderComparer.cs @@ -62,7 +62,7 @@ namespace MediaBrowser.Server.Implementations.Sorting return CompareEpisodes(x, y); } - if (!isXSpecial && isYSpecial) + if (!isXSpecial) { return CompareEpisodeToSpecial(x, y); } @@ -87,8 +87,17 @@ namespace MediaBrowser.Server.Implementations.Sorting // Add 1 to to non-specials to account for AirsBeforeEpisodeNumber var xEpisode = x.IndexNumber ?? -1; xEpisode++; + var yEpisode = y.AirsBeforeEpisodeNumber ?? 10000; + // Sometimes they'll both have a value. + // For example AirsAfterSeasonNumber=1, AirsBeforeSeasonNumber=2, AirsBeforeEpisodeNumber=1 + // The episode should be displayed at the end of season 1 + if (y.AirsAfterSeasonNumber.HasValue && y.AirsBeforeSeasonNumber.HasValue && y.AirsBeforeSeasonNumber.Value > y.AirsAfterSeasonNumber.Value) + { + yEpisode = 10000; + } + return xEpisode.CompareTo(yEpisode); } diff --git a/MediaBrowser.Server.Implementations/Sorting/NameComparer.cs b/MediaBrowser.Server.Implementations/Sorting/NameComparer.cs index 49f86c485..83b1b2d16 100644 --- a/MediaBrowser.Server.Implementations/Sorting/NameComparer.cs +++ b/MediaBrowser.Server.Implementations/Sorting/NameComparer.cs @@ -1,7 +1,6 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Sorting; using MediaBrowser.Model.Querying; -using System; namespace MediaBrowser.Server.Implementations.Sorting { @@ -18,7 +17,7 @@ namespace MediaBrowser.Server.Implementations.Sorting /// System.Int32. public int Compare(BaseItem x, BaseItem y) { - return string.Compare(x.Name, y.Name, StringComparison.CurrentCultureIgnoreCase); + return AlphanumComparator.CompareValues(x.Name, y.Name); } /// diff --git a/MediaBrowser.Server.Implementations/Sorting/SeriesSortNameComparer.cs b/MediaBrowser.Server.Implementations/Sorting/SeriesSortNameComparer.cs index 4efc3218b..09612a49c 100644 --- a/MediaBrowser.Server.Implementations/Sorting/SeriesSortNameComparer.cs +++ b/MediaBrowser.Server.Implementations/Sorting/SeriesSortNameComparer.cs @@ -16,7 +16,7 @@ namespace MediaBrowser.Server.Implementations.Sorting /// System.Int32. public int Compare(BaseItem x, BaseItem y) { - return string.Compare(GetValue(x), GetValue(y), StringComparison.CurrentCultureIgnoreCase); + return AlphanumComparator.CompareValues(GetValue(x), GetValue(y)); } private string GetValue(BaseItem item) -- cgit v1.2.3 From d7c25fa53f636d9882b6fd77bc877fc71ddd8902 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 8 Dec 2013 21:24:23 -0500 Subject: fixed issue with natural sort --- .../Sorting/AlphanumComparator.cs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'MediaBrowser.Server.Implementations/Sorting') diff --git a/MediaBrowser.Server.Implementations/Sorting/AlphanumComparator.cs b/MediaBrowser.Server.Implementations/Sorting/AlphanumComparator.cs index 2ced9a566..3fbb01f77 100644 --- a/MediaBrowser.Server.Implementations/Sorting/AlphanumComparator.cs +++ b/MediaBrowser.Server.Implementations/Sorting/AlphanumComparator.cs @@ -33,8 +33,8 @@ namespace MediaBrowser.Server.Implementations.Sorting return 0; } - var thisMarker = 0; - var thatMarker = 0; + int thisMarker = 0, thisNumericChunk = 0; + int thatMarker = 0, thatNumericChunk = 0; while ((thisMarker < s1.Length) || (thatMarker < s2.Length)) { @@ -42,15 +42,15 @@ namespace MediaBrowser.Server.Implementations.Sorting { return -1; } - if (thatMarker >= s2.Length) + else if (thatMarker >= s2.Length) { return 1; } - var thisCh = s1[thisMarker]; - var thatCh = s2[thatMarker]; + char thisCh = s1[thisMarker]; + char thatCh = s2[thatMarker]; - var thisChunk = new StringBuilder(); - var thatChunk = new StringBuilder(); + StringBuilder thisChunk = new StringBuilder(); + StringBuilder thatChunk = new StringBuilder(); while ((thisMarker < s1.Length) && (thisChunk.Length == 0 || InChunk(thisCh, thisChunk[0]))) { @@ -78,8 +78,8 @@ namespace MediaBrowser.Server.Implementations.Sorting // 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()); + thisNumericChunk = Convert.ToInt32(thisChunk.ToString()); + thatNumericChunk = Convert.ToInt32(thatChunk.ToString()); if (thisNumericChunk < thatNumericChunk) { @@ -93,7 +93,7 @@ namespace MediaBrowser.Server.Implementations.Sorting } else { - return string.Compare(thisChunk.ToString(), thatChunk.ToString(), StringComparison.CurrentCultureIgnoreCase); + result = thisChunk.ToString().CompareTo(thatChunk.ToString()); } if (result != 0) -- cgit v1.2.3