79 lines
2.1 KiB
C#
79 lines
2.1 KiB
C#
using System.Collections;
|
|
using System.Globalization;
|
|
|
|
namespace EmbyToolbox.Services;
|
|
|
|
public sealed class NaturalStringComparer : IComparer<string>, IComparer
|
|
{
|
|
public static readonly NaturalStringComparer Instance = new();
|
|
|
|
public int Compare(string? x, string? y)
|
|
{
|
|
if (ReferenceEquals(x, y))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (x is null)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if (y is null)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
var ix = 0;
|
|
var iy = 0;
|
|
while (ix < x.Length && iy < y.Length)
|
|
{
|
|
var cx = x[ix];
|
|
var cy = y[iy];
|
|
|
|
if (char.IsDigit(cx) && char.IsDigit(cy))
|
|
{
|
|
var startX = ix;
|
|
var startY = iy;
|
|
while (ix < x.Length && char.IsDigit(x[ix])) ix++;
|
|
while (iy < y.Length && char.IsDigit(y[iy])) iy++;
|
|
|
|
var partX = x[startX..ix].TrimStart('0');
|
|
var partY = y[startY..iy].TrimStart('0');
|
|
if (partX.Length != partY.Length)
|
|
{
|
|
return partX.Length.CompareTo(partY.Length);
|
|
}
|
|
|
|
var compareNumeric = string.Compare(partX, partY, StringComparison.Ordinal);
|
|
if (compareNumeric != 0)
|
|
{
|
|
return compareNumeric;
|
|
}
|
|
|
|
var rawX = x[startX..ix];
|
|
var rawY = y[startY..iy];
|
|
if (rawX.Length != rawY.Length)
|
|
{
|
|
return rawX.Length.CompareTo(rawY.Length);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var cmp = char.ToUpper(cx, CultureInfo.InvariantCulture).CompareTo(char.ToUpper(cy, CultureInfo.InvariantCulture));
|
|
if (cmp != 0)
|
|
{
|
|
return cmp;
|
|
}
|
|
|
|
ix++;
|
|
iy++;
|
|
}
|
|
}
|
|
|
|
return x.Length.CompareTo(y.Length);
|
|
}
|
|
|
|
int IComparer.Compare(object? x, object? y) => Compare(x as string, y as string);
|
|
}
|