using System.Collections; using System.Globalization; namespace EmbyToolbox.Services; public sealed class NaturalStringComparer : IComparer, 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); }