123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- #pragma warning disable CS1591
- using System;
- using System.Collections.Generic;
- namespace MediaBrowser.Controller.Sorting
- {
- public class AlphanumComparator : IComparer<string?>
- {
- public static int CompareValues(string? s1, string? s2)
- {
- if (s1 == null && s2 == null)
- {
- return 0;
- }
- else if (s1 == null)
- {
- return -1;
- }
- else if (s2 == null)
- {
- return 1;
- }
- int len1 = s1.Length;
- int len2 = s2.Length;
- // Early return for empty strings
- if (len1 == 0 && len2 == 0)
- {
- return 0;
- }
- else if (len1 == 0)
- {
- return -1;
- }
- else if (len2 == 0)
- {
- return 1;
- }
- int pos1 = 0;
- int pos2 = 0;
- do
- {
- int start1 = pos1;
- int start2 = pos2;
- bool isNum1 = char.IsDigit(s1[pos1++]);
- bool isNum2 = char.IsDigit(s2[pos2++]);
- while (pos1 < len1 && char.IsDigit(s1[pos1]) == isNum1)
- {
- pos1++;
- }
- while (pos2 < len2 && char.IsDigit(s2[pos2]) == isNum2)
- {
- pos2++;
- }
- var span1 = s1.AsSpan(start1, pos1 - start1);
- var span2 = s2.AsSpan(start2, pos2 - start2);
- if (isNum1 && isNum2)
- {
- // Trim leading zeros so we can compare the length
- // of the strings to find the largest number
- span1 = span1.TrimStart('0');
- span2 = span2.TrimStart('0');
- var span1Len = span1.Length;
- var span2Len = span2.Length;
- if (span1Len < span2Len)
- {
- return -1;
- }
- else if (span1Len > span2Len)
- {
- return 1;
- }
- else if (span1Len >= 20) // Number is probably too big for a ulong
- {
- // Trim all the first digits that are the same
- int i = 0;
- while (i < span1Len && span1[i] == span2[i])
- {
- i++;
- }
- // If there are no more digits it's the same number
- if (i == span1Len)
- {
- continue;
- }
- // Only need to compare the most significant digit
- span1 = span1.Slice(i, 1);
- span2 = span2.Slice(i, 1);
- }
- if (!ulong.TryParse(span1, out var num1)
- || !ulong.TryParse(span2, out var num2))
- {
- return 0;
- }
- else if (num1 < num2)
- {
- return -1;
- }
- else if (num1 > num2)
- {
- return 1;
- }
- }
- else
- {
- int result = span1.CompareTo(span2, StringComparison.InvariantCulture);
- if (result != 0)
- {
- return result;
- }
- }
- #pragma warning disable SA1500 // TODO remove with StyleCop.Analyzers v1.2.0 https://github.com/DotNetAnalyzers/StyleCopAnalyzers/pull/3196
- } while (pos1 < len1 && pos2 < len2);
- #pragma warning restore SA1500
- return len1 - len2;
- }
- /// <inheritdoc />
- public int Compare(string? x, string? y)
- {
- return CompareValues(x, y);
- }
- }
- }
|