diff --git a/Pages/Index.cshtml.cs b/Pages/Index.cshtml.cs index e52d400..cf64a4f 100644 --- a/Pages/Index.cshtml.cs +++ b/Pages/Index.cshtml.cs @@ -1,4 +1,4 @@ -using System; +using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; @@ -36,7 +36,7 @@ namespace webmusic.Pages dirs.Sort(); files = Directory.GetFiles(fullpath).Select(Path.GetFileName).ToList(); files.RemoveAll(p => p.EndsWith(".m3u")); - files.Sort(new NumericComparer()); + files.Sort(new AlphanumComparatorFast()); } public string Encode(string str) @@ -45,25 +45,96 @@ namespace webmusic.Pages .Replace("?", "%3F").Replace("&", "%26") .Replace(" ", "%20"); } - - public class NumericComparer : IComparer + + public class AlphanumComparatorFast : IComparer { public int Compare(string x, string y) { - var regex = new Regex(@"^\d+"); - - // run the regex on both strings - var xRegexResult = regex.Match(x); - var yRegexResult = regex.Match(y); - - // check if they are both numbers - if (xRegexResult.Success && yRegexResult.Success) + string s1 = x; + if (s1 == null) { - return int.Parse(xRegexResult.Value).CompareTo(int.Parse(yRegexResult.Value)); + return 0; } - // otherwise return as string comparison - return string.Compare(x, y, StringComparison.Ordinal); + if (!(y is string s2)) + { + return 0; + } + + int len1 = s1.Length; + int len2 = s2.Length; + int marker1 = 0; + int marker2 = 0; + + // Walk through two the strings with two markers. + while (marker1 < len1 && marker2 < len2) + { + char ch1 = s1[marker1]; + char ch2 = s2[marker2]; + + // Some buffers we can build up characters in for each chunk. + char[] space1 = new char[len1]; + int loc1 = 0; + char[] space2 = new char[len2]; + int loc2 = 0; + + // Walk through all following characters that are digits or + // characters in BOTH strings starting at the appropriate marker. + // Collect char arrays. + do + { + space1[loc1++] = ch1; + marker1++; + + if (marker1 < len1) + { + ch1 = s1[marker1]; + } + else + { + break; + } + } while (char.IsDigit(ch1) == char.IsDigit(space1[0])); + + do + { + space2[loc2++] = ch2; + marker2++; + + if (marker2 < len2) + { + ch2 = s2[marker2]; + } + else + { + break; + } + } while (char.IsDigit(ch2) == char.IsDigit(space2[0])); + + // If we have collected numbers, compare them numerically. + // Otherwise, if we have strings, compare them alphabetically. + string str1 = new string(space1); + string str2 = new string(space2); + + int result; + + if (char.IsDigit(space1[0]) && char.IsDigit(space2[0])) + { + int thisNumericChunk = int.Parse(str1); + int thatNumericChunk = int.Parse(str2); + result = thisNumericChunk.CompareTo(thatNumericChunk); + } + else + { + result = str1.CompareTo(str2); + } + + if (result != 0) + { + return result; + } + } + return len1 - len2; } } }