Replace AlphanumericComparator with new CompareOptions.NumericOrdering

This commit is contained in:
Bond_009 2025-11-16 19:31:45 +01:00
parent 1ba8e2c93c
commit 098e8c6fed
5 changed files with 18 additions and 153 deletions

View file

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
@ -136,19 +137,27 @@ namespace Emby.Naming.Video
if (videos.Count > 1) if (videos.Count > 1)
{ {
var groups = videos.GroupBy(x => ResolutionRegex().IsMatch(x.Files[0].FileNameWithoutExtension)).ToList(); var groups = videos
.Select(x => (filename: x.Files[0].FileNameWithoutExtension.ToString(), value: x))
.Select(x => (x.filename, resolutionMatch: ResolutionRegex().Match(x.filename), x.value))
.GroupBy(x => x.resolutionMatch.Success)
.ToList();
videos.Clear(); videos.Clear();
StringComparer comparer = StringComparer.Create(CultureInfo.InvariantCulture, CompareOptions.NumericOrdering);
foreach (var group in groups) foreach (var group in groups)
{ {
if (group.Key) if (group.Key)
{ {
videos.InsertRange(0, group videos.InsertRange(0, group
.OrderByDescending(x => ResolutionRegex().Match(x.Files[0].FileNameWithoutExtension.ToString()).Value, new AlphanumericComparator()) .OrderByDescending(x => x.resolutionMatch.Value, comparer)
.ThenBy(x => x.Files[0].FileNameWithoutExtension.ToString(), new AlphanumericComparator())); .ThenBy(x => x.filename, comparer)
.Select(x => x.value));
} }
else else
{ {
videos.AddRange(group.OrderBy(x => x.Files[0].FileNameWithoutExtension.ToString(), new AlphanumericComparator())); videos.AddRange(group.OrderBy(x => x.filename, comparer).Select(x => x.value));
} }
} }
} }

View file

@ -1,11 +1,11 @@
#pragma warning disable CS1591 #pragma warning disable CS1591
using System; using System;
using System.Globalization;
using Jellyfin.Data.Enums; using Jellyfin.Data.Enums;
using Jellyfin.Extensions; using Jellyfin.Extensions;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Sorting; using MediaBrowser.Controller.Sorting;
using MediaBrowser.Model.Querying;
namespace Emby.Server.Implementations.Sorting namespace Emby.Server.Implementations.Sorting
{ {
@ -28,7 +28,7 @@ namespace Emby.Server.Implementations.Sorting
ArgumentNullException.ThrowIfNull(x); ArgumentNullException.ThrowIfNull(x);
ArgumentNullException.ThrowIfNull(y); ArgumentNullException.ThrowIfNull(y);
return AlphanumericComparator.CompareValues(x.Studios.FirstOrDefault(), y.Studios.FirstOrDefault()); return CultureInfo.InvariantCulture.CompareInfo.Compare(x.Studios.FirstOrDefault(), y.Studios.FirstOrDefault(), CompareOptions.NumericOrdering);
} }
} }
} }

View file

@ -1,7 +1,9 @@
#pragma warning disable CS1591 #pragma warning disable CS1591
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.Linq; using System.Linq;
using Jellyfin.Extensions; using Jellyfin.Extensions;
@ -9,7 +11,7 @@ namespace MediaBrowser.Controller.Sorting
{ {
public static class SortExtensions public static class SortExtensions
{ {
private static readonly AlphanumericComparator _comparer = new AlphanumericComparator(); private static readonly StringComparer _comparer = StringComparer.Create(CultureInfo.InvariantCulture, CompareOptions.NumericOrdering);
public static IEnumerable<T> OrderByString<T>(this IEnumerable<T> list, Func<T, string> getName) public static IEnumerable<T> OrderByString<T>(this IEnumerable<T> list, Func<T, string> getName)
{ {

View file

@ -1,112 +0,0 @@
using System;
using System.Collections.Generic;
namespace Jellyfin.Extensions
{
/// <summary>
/// Alphanumeric <see cref="IComparer{T}" />.
/// </summary>
public class AlphanumericComparator : IComparer<string?>
{
/// <summary>
/// Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the other.
/// </summary>
/// <param name="s1">The first object to compare.</param>
/// <param name="s2">The second object to compare.</param>
/// <returns>A signed integer that indicates the relative values of <c>x</c> and <c>y</c>.</returns>
public static int CompareValues(string? s1, string? s2)
{
if (s1 is null && s2 is null)
{
return 0;
}
if (s1 is null)
{
return -1;
}
if (s2 is null)
{
return 1;
}
int len1 = s1.Length;
int len2 = s2.Length;
// Early return for empty strings
if (len1 == 0 && len2 == 0)
{
return 0;
}
if (len1 == 0)
{
return -1;
}
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;
}
if (span1Len > span2Len)
{
return 1;
}
}
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);
}
}
}

View file

@ -1,34 +0,0 @@
using System;
using System.Linq;
using Xunit;
namespace Jellyfin.Extensions.Tests
{
public class AlphanumericComparatorTests
{
// InlineData is pre-sorted
[Theory]
[InlineData(null, "", "1", "9", "10", "a", "z")]
[InlineData("50F", "100F", "SR9", "SR100")]
[InlineData("image-1.jpg", "image-02.jpg", "image-4.jpg", "image-9.jpg", "image-10.jpg", "image-11.jpg", "image-22.jpg")]
[InlineData("Hard drive 2GB", "Hard drive 20GB")]
[InlineData("b", "e", "è", "ě", "f", "g", "k")]
[InlineData("123456789", "123456789a", "abc", "abcd")]
[InlineData("12345678912345678912345678913234567891", "123456789123456789123456789132345678912")]
[InlineData("12345678912345678912345678913234567891", "12345678912345678912345678913234567891")]
[InlineData("12345678912345678912345678913234567891", "12345678912345678912345678913234567892")]
[InlineData("12345678912345678912345678913234567891a", "12345678912345678912345678913234567891a")]
[InlineData("12345678912345678912345678913234567891a", "12345678912345678912345678913234567891b")]
[InlineData("a5", "a11")]
[InlineData("a05a", "a5b")]
[InlineData("a5a", "a05b")]
[InlineData("6xxx", "007asdf")]
[InlineData("00042Q", "42s")]
public void AlphanumericComparatorTest(params string?[] strings)
{
var copy = strings.Reverse().ToArray();
Array.Sort(copy, new AlphanumericComparator());
Assert.Equal(strings, copy);
}
}
}