mirror of
				https://github.com/jellyfin/jellyfin.git
				synced 2025-11-04 03:27:21 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			136 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			136 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
#nullable enable
 | 
						|
 | 
						|
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;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            } while (pos1 < len1 && pos2 < len2);
 | 
						|
 | 
						|
            return len1 - len2;
 | 
						|
        }
 | 
						|
 | 
						|
        /// <inheritdoc />
 | 
						|
        public int Compare(string x, string y)
 | 
						|
        {
 | 
						|
            return CompareValues(x, y);
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |