mirror of
				https://github.com/jellyfin/jellyfin.git
				synced 2025-11-03 19:17:24 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			144 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			144 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
using System;
 | 
						|
using System.Collections.Generic;
 | 
						|
using System.Linq;
 | 
						|
using System.Text;
 | 
						|
 | 
						|
namespace MediaBrowser.Controller.Sorting
 | 
						|
{
 | 
						|
    public static class SortExtensions
 | 
						|
    {
 | 
						|
        public static IEnumerable<T> OrderByString<T>(this IEnumerable<T> list, Func<T, string> getName)
 | 
						|
        {
 | 
						|
            return list.OrderBy(getName, new AlphanumComparator());
 | 
						|
        }
 | 
						|
 | 
						|
        public static IEnumerable<T> OrderByStringDescending<T>(this IEnumerable<T> list, Func<T, string> getName)
 | 
						|
        {
 | 
						|
            return list.OrderByDescending(getName, new AlphanumComparator());
 | 
						|
        }
 | 
						|
 | 
						|
        public static IOrderedEnumerable<T> ThenByString<T>(this IOrderedEnumerable<T> list, Func<T, string> getName)
 | 
						|
        {
 | 
						|
            return list.ThenBy(getName, new AlphanumComparator());
 | 
						|
        }
 | 
						|
 | 
						|
        public static IOrderedEnumerable<T> ThenByStringDescending<T>(this IOrderedEnumerable<T> list, Func<T, string> getName)
 | 
						|
        {
 | 
						|
            return list.ThenByDescending(getName, new AlphanumComparator());
 | 
						|
        }
 | 
						|
 | 
						|
        private 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;
 | 
						|
                }
 | 
						|
 | 
						|
                int thisMarker = 0, thisNumericChunk = 0;
 | 
						|
                int thatMarker = 0, thatNumericChunk = 0;
 | 
						|
 | 
						|
                while ((thisMarker < s1.Length) || (thatMarker < s2.Length))
 | 
						|
                {
 | 
						|
                    if (thisMarker >= s1.Length)
 | 
						|
                    {
 | 
						|
                        return -1;
 | 
						|
                    }
 | 
						|
                    else if (thatMarker >= s2.Length)
 | 
						|
                    {
 | 
						|
                        return 1;
 | 
						|
                    }
 | 
						|
                    char thisCh = s1[thisMarker];
 | 
						|
                    char 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]))
 | 
						|
                    {
 | 
						|
                        if (!int.TryParse(thisChunk.ToString(), out thisNumericChunk))
 | 
						|
                        {
 | 
						|
                            return 0;
 | 
						|
                        }
 | 
						|
                        if (!int.TryParse(thatChunk.ToString(), out thatNumericChunk))
 | 
						|
                        {
 | 
						|
                            return 0;
 | 
						|
                        }
 | 
						|
 | 
						|
                        if (thisNumericChunk < thatNumericChunk)
 | 
						|
                        {
 | 
						|
                            result = -1;
 | 
						|
                        }
 | 
						|
 | 
						|
                        if (thisNumericChunk > thatNumericChunk)
 | 
						|
                        {
 | 
						|
                            result = 1;
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    else
 | 
						|
                    {
 | 
						|
                        result = thisChunk.ToString().CompareTo(thatChunk.ToString());
 | 
						|
                    }
 | 
						|
 | 
						|
                    if (result != 0)
 | 
						|
                    {
 | 
						|
                        return result;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
 | 
						|
                return 0;
 | 
						|
            }
 | 
						|
 | 
						|
            public int Compare(string x, string y)
 | 
						|
            {
 | 
						|
                return CompareValues(x, y);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |