mirror of
https://github.com/SabreTools/SabreTools.Matching.git
synced 2026-02-08 13:49:55 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
08ef69e7c1 | ||
|
|
19971ec62c | ||
|
|
4650399bc1 | ||
|
|
aad97d03fd | ||
|
|
85bc696ba9 | ||
|
|
8fcce5b450 | ||
|
|
cd04d2d64c | ||
|
|
3e0267eedb | ||
|
|
70aeabd355 |
43
.github/workflows/build_nupkg.yml
vendored
Normal file
43
.github/workflows/build_nupkg.yml
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
name: Nuget Pack
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
|
||||
- name: Pack
|
||||
run: dotnet pack
|
||||
|
||||
- name: Upload build
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: 'Nuget Package'
|
||||
path: 'bin/Release/*.nupkg'
|
||||
|
||||
- name: Upload to rolling
|
||||
uses: ncipollo/release-action@v1.14.0
|
||||
with:
|
||||
allowUpdates: True
|
||||
artifacts: 'bin/Release/*.nupkg'
|
||||
body: 'Last built commit: ${{ github.sha }}'
|
||||
name: 'Rolling Release'
|
||||
prerelease: True
|
||||
replacesArtifacts: True
|
||||
tag: "rolling"
|
||||
updateOnlyUnreleased: True
|
||||
17
.github/workflows/check_pr.yml
vendored
Normal file
17
.github/workflows/check_pr.yml
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
name: Build PR
|
||||
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
|
||||
- name: Build
|
||||
run: dotnet build
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
@@ -5,13 +6,21 @@ namespace SabreTools.Matching
|
||||
{
|
||||
public static class Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates whether the specified array is null or has a length of zero
|
||||
/// </summary>
|
||||
public static bool IsNullOrEmpty(this Array? array)
|
||||
{
|
||||
return array == null || array.Length == 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find all positions of one array in another, if possible, if possible
|
||||
/// </summary>
|
||||
public static List<int> FindAllPositions(this byte[] stack, byte?[]? needle, int start = 0, int end = -1)
|
||||
{
|
||||
// Get the outgoing list
|
||||
List<int> positions = new List<int>();
|
||||
List<int> positions = [];
|
||||
|
||||
// Initialize the loop variables
|
||||
bool found = true;
|
||||
@@ -35,7 +44,7 @@ namespace SabreTools.Matching
|
||||
/// </summary>
|
||||
public static bool FirstPosition(this byte[] stack, byte[]? needle, out int position, int start = 0, int end = -1)
|
||||
{
|
||||
byte?[]? nullableNeedle = needle != null ? needle.Select(b => (byte?)b).ToArray() : null;
|
||||
byte?[]? nullableNeedle = needle?.Select(b => (byte?)b).ToArray();
|
||||
return stack.FirstPosition(nullableNeedle, out position, start, end);
|
||||
}
|
||||
|
||||
@@ -64,10 +73,16 @@ namespace SabreTools.Matching
|
||||
/// <summary>
|
||||
/// See if a byte array starts with another
|
||||
/// </summary>
|
||||
public static bool StartsWith(this byte[] stack, byte[]? needle)
|
||||
public static bool StartsWith(this byte[] stack, byte[]? needle, bool exact = false)
|
||||
{
|
||||
if (needle == null)
|
||||
// If we have any invalid inputs, we return false
|
||||
if (needle == null
|
||||
|| stack.Length == 0 || needle.Length == 0
|
||||
|| needle.Length > stack.Length
|
||||
|| (exact && stack.Length != needle.Length))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return stack.FirstPosition(needle, out int _, start: 0, end: 1);
|
||||
}
|
||||
@@ -75,10 +90,16 @@ namespace SabreTools.Matching
|
||||
/// <summary>
|
||||
/// See if a byte array starts with another
|
||||
/// </summary>
|
||||
public static bool StartsWith(this byte[] stack, byte?[]? needle)
|
||||
public static bool StartsWith(this byte[] stack, byte?[]? needle, bool exact = false)
|
||||
{
|
||||
if (needle == null)
|
||||
// If we have any invalid inputs, we return false
|
||||
if (needle == null
|
||||
|| stack.Length == 0 || needle.Length == 0
|
||||
|| needle.Length > stack.Length
|
||||
|| (exact && stack.Length != needle.Length))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return stack.FirstPosition(needle, out int _, start: 0, end: 1);
|
||||
}
|
||||
@@ -86,10 +107,16 @@ namespace SabreTools.Matching
|
||||
/// <summary>
|
||||
/// See if a byte array ends with another
|
||||
/// </summary>
|
||||
public static bool EndsWith(this byte[] stack, byte[]? needle)
|
||||
public static bool EndsWith(this byte[] stack, byte[]? needle, bool exact = false)
|
||||
{
|
||||
if (needle == null)
|
||||
// If we have any invalid inputs, we return false
|
||||
if (needle == null
|
||||
|| stack.Length == 0 || needle.Length == 0
|
||||
|| needle.Length > stack.Length
|
||||
|| (exact && stack.Length != needle.Length))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return stack.FirstPosition(needle, out int _, start: stack.Length - needle.Length);
|
||||
}
|
||||
@@ -97,10 +124,16 @@ namespace SabreTools.Matching
|
||||
/// <summary>
|
||||
/// See if a byte array ends with another
|
||||
/// </summary>
|
||||
public static bool EndsWith(this byte[] stack, byte?[]? needle)
|
||||
public static bool EndsWith(this byte[] stack, byte?[]? needle, bool exact = false)
|
||||
{
|
||||
if (needle == null)
|
||||
// If we have any invalid inputs, we return false
|
||||
if (needle == null
|
||||
|| stack.Length == 0 || needle.Length == 0
|
||||
|| needle.Length > stack.Length
|
||||
|| (exact && stack.Length != needle.Length))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return stack.FirstPosition(needle, out int _, start: stack.Length - needle.Length);
|
||||
}
|
||||
|
||||
50
MatchUtil.cs
50
MatchUtil.cs
@@ -1,4 +1,6 @@
|
||||
#if NET40_OR_GREATER || NETCOREAPP
|
||||
using System.Collections.Concurrent;
|
||||
#endif
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -20,7 +22,11 @@ namespace SabreTools.Matching
|
||||
/// <param name="matchers">Enumerable of ContentMatchSets to be run on the file</param>
|
||||
/// <param name="includeDebug">True to include positional data, false otherwise</param>
|
||||
/// <returns>List of strings representing the matched protections, null or empty otherwise</returns>
|
||||
#if NET20 || NET35
|
||||
public static Queue<string>? GetAllMatches(string file, byte[]? stack, IEnumerable<ContentMatchSet>? matchers, bool includeDebug = false)
|
||||
#else
|
||||
public static ConcurrentQueue<string>? GetAllMatches(string file, byte[]? stack, IEnumerable<ContentMatchSet>? matchers, bool includeDebug = false)
|
||||
#endif
|
||||
{
|
||||
return FindAllMatches(file, stack, matchers, includeDebug, false);
|
||||
}
|
||||
@@ -51,14 +57,22 @@ namespace SabreTools.Matching
|
||||
/// <param name="includeDebug">True to include positional data, false otherwise</param>
|
||||
/// <param name="stopAfterFirst">True to stop after the first match, false otherwise</param>
|
||||
/// <returns>List of strings representing the matched protections, null or empty otherwise</returns>
|
||||
#if NET20 || NET35
|
||||
private static Queue<string>? FindAllMatches(string file, byte[]? stack, IEnumerable<ContentMatchSet>? matchers, bool includeDebug, bool stopAfterFirst)
|
||||
#else
|
||||
private static ConcurrentQueue<string>? FindAllMatches(string file, byte[]? stack, IEnumerable<ContentMatchSet>? matchers, bool includeDebug, bool stopAfterFirst)
|
||||
#endif
|
||||
{
|
||||
// If there's no mappings, we can't match
|
||||
if (matchers == null || !matchers.Any())
|
||||
return null;
|
||||
|
||||
// Initialize the queue of matched protections
|
||||
#if NET20 || NET35
|
||||
var matchedProtections = new Queue<string>();
|
||||
#else
|
||||
var matchedProtections = new ConcurrentQueue<string>();
|
||||
#endif
|
||||
|
||||
// Loop through and try everything otherwise
|
||||
foreach (var matcher in matchers)
|
||||
@@ -75,7 +89,7 @@ namespace SabreTools.Matching
|
||||
{
|
||||
positionStrs.Add(pos.ToString());
|
||||
}
|
||||
string positionsString = string.Join(", ", positionStrs.ToArray());
|
||||
string positionsString = string.Join(", ", [.. positionStrs]);
|
||||
#else
|
||||
string positionsString = string.Join(", ", positions);
|
||||
#endif
|
||||
@@ -117,7 +131,11 @@ namespace SabreTools.Matching
|
||||
/// <param name="matchers">Enumerable of ContentMatchSets to be run on the file</param>
|
||||
/// <param name="includeDebug">True to include positional data, false otherwise</param>
|
||||
/// <returns>List of strings representing the matched protections, null or empty otherwise</returns>
|
||||
#if NET20 || NET35
|
||||
public static Queue<string>? GetAllMatches(string file, Stream? stack, IEnumerable<ContentMatchSet>? matchers, bool includeDebug = false)
|
||||
#else
|
||||
public static ConcurrentQueue<string>? GetAllMatches(string file, Stream? stack, IEnumerable<ContentMatchSet>? matchers, bool includeDebug = false)
|
||||
#endif
|
||||
{
|
||||
return FindAllMatches(file, stack, matchers, includeDebug, false);
|
||||
}
|
||||
@@ -148,14 +166,22 @@ namespace SabreTools.Matching
|
||||
/// <param name="includeDebug">True to include positional data, false otherwise</param>
|
||||
/// <param name="stopAfterFirst">True to stop after the first match, false otherwise</param>
|
||||
/// <returns>List of strings representing the matched protections, null or empty otherwise</returns>
|
||||
#if NET20 || NET35
|
||||
private static Queue<string>? FindAllMatches(string file, Stream? stack, IEnumerable<ContentMatchSet>? matchers, bool includeDebug, bool stopAfterFirst)
|
||||
#else
|
||||
private static ConcurrentQueue<string>? FindAllMatches(string file, Stream? stack, IEnumerable<ContentMatchSet>? matchers, bool includeDebug, bool stopAfterFirst)
|
||||
#endif
|
||||
{
|
||||
// If there's no mappings, we can't match
|
||||
if (matchers == null || !matchers.Any())
|
||||
return null;
|
||||
|
||||
// Initialize the queue of matched protections
|
||||
#if NET20 || NET35
|
||||
var matchedProtections = new Queue<string>();
|
||||
#else
|
||||
var matchedProtections = new ConcurrentQueue<string>();
|
||||
#endif
|
||||
|
||||
// Loop through and try everything otherwise
|
||||
foreach (var matcher in matchers)
|
||||
@@ -172,7 +198,7 @@ namespace SabreTools.Matching
|
||||
{
|
||||
positionStrs.Add(pos.ToString());
|
||||
}
|
||||
string positionsString = string.Join(", ", positionStrs.ToArray());
|
||||
string positionsString = string.Join(", ", [.. positionStrs]);
|
||||
#else
|
||||
string positionsString = string.Join(", ", positions);
|
||||
#endif
|
||||
@@ -213,7 +239,11 @@ namespace SabreTools.Matching
|
||||
/// <param name="matchers">Enumerable of PathMatchSets to be run on the file</param>
|
||||
/// <param name="any">True if any path match is a success, false if all have to match</param>
|
||||
/// <returns>List of strings representing the matched protections, null or empty otherwise</returns>
|
||||
#if NET20 || NET35
|
||||
public static Queue<string> GetAllMatches(string file, IEnumerable<PathMatchSet>? matchers, bool any = false)
|
||||
#else
|
||||
public static ConcurrentQueue<string> GetAllMatches(string file, IEnumerable<PathMatchSet>? matchers, bool any = false)
|
||||
#endif
|
||||
{
|
||||
return FindAllMatches(new List<string> { file }, matchers, any, false);
|
||||
}
|
||||
@@ -225,7 +255,11 @@ namespace SabreTools.Matching
|
||||
/// <param name="matchers">Enumerable of PathMatchSets to be run on the file</param>
|
||||
/// <param name="any">True if any path match is a success, false if all have to match</param>
|
||||
/// <returns>List of strings representing the matched protections, null or empty otherwise</returns>
|
||||
#if NET20 || NET35
|
||||
public static Queue<string> GetAllMatches(IEnumerable<string>? files, IEnumerable<PathMatchSet>? matchers, bool any = false)
|
||||
#else
|
||||
public static ConcurrentQueue<string> GetAllMatches(IEnumerable<string>? files, IEnumerable<PathMatchSet>? matchers, bool any = false)
|
||||
#endif
|
||||
{
|
||||
return FindAllMatches(files, matchers, any, false);
|
||||
}
|
||||
@@ -270,21 +304,29 @@ namespace SabreTools.Matching
|
||||
/// <param name="any">True if any path match is a success, false if all have to match</param>
|
||||
/// <param name="stopAfterFirst">True to stop after the first match, false otherwise</param>
|
||||
/// <returns>List of strings representing the matched protections, null or empty otherwise</returns>
|
||||
#if NET20 || NET35
|
||||
private static Queue<string> FindAllMatches(IEnumerable<string>? files, IEnumerable<PathMatchSet>? matchers, bool any, bool stopAfterFirst)
|
||||
#else
|
||||
private static ConcurrentQueue<string> FindAllMatches(IEnumerable<string>? files, IEnumerable<PathMatchSet>? matchers, bool any, bool stopAfterFirst)
|
||||
#endif
|
||||
{
|
||||
// If there's no mappings, we can't match
|
||||
if (matchers == null || !matchers.Any())
|
||||
return new ConcurrentQueue<string>();
|
||||
return new();
|
||||
|
||||
// Initialize the list of matched protections
|
||||
#if NET20 || NET35
|
||||
var matchedProtections = new Queue<string>();
|
||||
#else
|
||||
var matchedProtections = new ConcurrentQueue<string>();
|
||||
#endif
|
||||
|
||||
// Loop through and try everything otherwise
|
||||
foreach (var matcher in matchers)
|
||||
{
|
||||
// Determine if the matcher passes
|
||||
bool passes;
|
||||
var firstMatchedString = string.Empty;
|
||||
string? firstMatchedString;
|
||||
if (any)
|
||||
{
|
||||
(bool anyPasses, var matchedString) = matcher.MatchesAny(files);
|
||||
|
||||
103
NaturalComparer.cs
Normal file
103
NaturalComparer.cs
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
*
|
||||
* Links for info and original source code:
|
||||
*
|
||||
* https://blog.codinghorror.com/sorting-for-humans-natural-sort-order/
|
||||
* http://www.codeproject.com/Articles/22517/Natural-Sort-Comparer
|
||||
*
|
||||
* Exact code implementation used with permission, originally by motoschifo
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace SabreTools.Matching
|
||||
{
|
||||
public class NaturalComparer : Comparer<string>, IDisposable
|
||||
{
|
||||
private readonly Dictionary<string, string[]> table;
|
||||
|
||||
public NaturalComparer()
|
||||
{
|
||||
table = [];
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
table.Clear();
|
||||
}
|
||||
|
||||
public override int Compare(string? x, string? y)
|
||||
{
|
||||
if (x == null || y == null)
|
||||
{
|
||||
if (x == null && y != null)
|
||||
return -1;
|
||||
else if (x != null && y == null)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
if (x.ToLowerInvariant() == y.ToLowerInvariant())
|
||||
{
|
||||
return x.CompareTo(y);
|
||||
}
|
||||
if (!table.TryGetValue(x, out string[]? x1))
|
||||
{
|
||||
//x1 = Regex.Split(x.Replace(" ", string.Empty), "([0-9]+)");
|
||||
x1 = Regex.Split(x.ToLowerInvariant(), "([0-9]+)").Where(s => !string.IsNullOrEmpty(s)).ToArray();
|
||||
table.Add(x, x1);
|
||||
}
|
||||
if (!table.TryGetValue(y, out string[]? y1))
|
||||
{
|
||||
//y1 = Regex.Split(y.Replace(" ", string.Empty), "([0-9]+)");
|
||||
y1 = Regex.Split(y.ToLowerInvariant(), "([0-9]+)").Where(s => !string.IsNullOrEmpty(s)).ToArray();
|
||||
table.Add(y, y1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < x1.Length && i < y1.Length; i++)
|
||||
{
|
||||
if (x1[i] != y1[i])
|
||||
{
|
||||
return PartCompare(x1[i], y1[i]);
|
||||
}
|
||||
}
|
||||
if (y1.Length > x1.Length)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if (x1.Length > y1.Length)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return x.CompareTo(y);
|
||||
}
|
||||
}
|
||||
|
||||
private static int PartCompare(string left, string right)
|
||||
{
|
||||
if (!long.TryParse(left, out long x))
|
||||
{
|
||||
return NaturalComparerUtil.CompareNumeric(left, right);
|
||||
}
|
||||
|
||||
if (!long.TryParse(right, out long y))
|
||||
{
|
||||
return NaturalComparerUtil.CompareNumeric(left, right);
|
||||
}
|
||||
|
||||
// If we have an equal part, then make sure that "longer" ones are taken into account
|
||||
if (x.CompareTo(y) == 0)
|
||||
{
|
||||
return left.Length - right.Length;
|
||||
}
|
||||
|
||||
return x.CompareTo(y);
|
||||
}
|
||||
}
|
||||
}
|
||||
78
NaturalComparerUtil.cs
Normal file
78
NaturalComparerUtil.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using System.IO;
|
||||
|
||||
namespace SabreTools.Matching
|
||||
{
|
||||
public static class NaturalComparerUtil
|
||||
{
|
||||
public static int CompareNumeric(string s1, string s2)
|
||||
{
|
||||
// Save the orginal strings, for later comparison
|
||||
string s1orig = s1;
|
||||
string s2orig = s2;
|
||||
|
||||
// We want to normalize the strings, so we set both to lower case
|
||||
s1 = s1.ToLowerInvariant();
|
||||
s2 = s2.ToLowerInvariant();
|
||||
|
||||
// If the strings are the same exactly, return
|
||||
if (s1 == s2)
|
||||
return s1orig.CompareTo(s2orig);
|
||||
|
||||
// If one is null, then say that's less than
|
||||
if (s1 == null)
|
||||
return -1;
|
||||
if (s2 == null)
|
||||
return 1;
|
||||
|
||||
// Now split into path parts after converting AltDirSeparator to DirSeparator
|
||||
s1 = s1.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
|
||||
s2 = s2.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
|
||||
string[] s1parts = s1.Split(Path.DirectorySeparatorChar);
|
||||
string[] s2parts = s2.Split(Path.DirectorySeparatorChar);
|
||||
|
||||
// Then compare each part in turn
|
||||
for (int j = 0; j < s1parts.Length && j < s2parts.Length; j++)
|
||||
{
|
||||
int compared = CompareNumericPart(s1parts[j], s2parts[j]);
|
||||
if (compared != 0)
|
||||
return compared;
|
||||
}
|
||||
|
||||
// If we got out here, then it looped through at least one of the strings
|
||||
if (s1parts.Length > s2parts.Length)
|
||||
return 1;
|
||||
if (s1parts.Length < s2parts.Length)
|
||||
return -1;
|
||||
|
||||
return s1orig.CompareTo(s2orig);
|
||||
}
|
||||
|
||||
private static int CompareNumericPart(string s1, string s2)
|
||||
{
|
||||
// Otherwise, loop through until we have an answer
|
||||
for (int i = 0; i < s1.Length && i < s2.Length; i++)
|
||||
{
|
||||
int s1c = s1[i];
|
||||
int s2c = s2[i];
|
||||
|
||||
// If the characters are the same, continue
|
||||
if (s1c == s2c)
|
||||
continue;
|
||||
|
||||
// If they're different, check which one was larger
|
||||
if (s1c > s2c)
|
||||
return 1;
|
||||
if (s1c < s2c)
|
||||
return -1;
|
||||
}
|
||||
|
||||
// If we got out here, then it looped through at least one of the strings
|
||||
if (s1.Length > s2.Length)
|
||||
return 1;
|
||||
if (s1.Length < s2.Length)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
103
NaturalReversedComparer.cs
Normal file
103
NaturalReversedComparer.cs
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
*
|
||||
* Links for info and original source code:
|
||||
*
|
||||
* https://blog.codinghorror.com/sorting-for-humans-natural-sort-order/
|
||||
* http://www.codeproject.com/Articles/22517/Natural-Sort-Comparer
|
||||
*
|
||||
* Exact code implementation used with permission, originally by motoschifo
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace SabreTools.Matching
|
||||
{
|
||||
public class NaturalReversedComparer : Comparer<string>, IDisposable
|
||||
{
|
||||
private readonly Dictionary<string, string[]> table;
|
||||
|
||||
public NaturalReversedComparer()
|
||||
{
|
||||
table = [];
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
table.Clear();
|
||||
}
|
||||
|
||||
public override int Compare(string? x, string? y)
|
||||
{
|
||||
if (x == null || y == null)
|
||||
{
|
||||
if (x == null && y != null)
|
||||
return -1;
|
||||
else if (x != null && y == null)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
if (y.ToLowerInvariant() == x.ToLowerInvariant())
|
||||
{
|
||||
return y.CompareTo(x);
|
||||
}
|
||||
if (!table.TryGetValue(x, out string[]? x1))
|
||||
{
|
||||
//x1 = Regex.Split(x.Replace(" ", string.Empty), "([0-9]+)");
|
||||
x1 = Regex.Split(x.ToLowerInvariant(), "([0-9]+)").Where(s => !string.IsNullOrEmpty(s)).ToArray();
|
||||
table.Add(x, x1);
|
||||
}
|
||||
if (!table.TryGetValue(y, out string[]? y1))
|
||||
{
|
||||
//y1 = Regex.Split(y.Replace(" ", string.Empty), "([0-9]+)");
|
||||
y1 = Regex.Split(y.ToLowerInvariant(), "([0-9]+)").Where(s => !string.IsNullOrEmpty(s)).ToArray();
|
||||
table.Add(y, y1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < x1.Length && i < y1.Length; i++)
|
||||
{
|
||||
if (x1[i] != y1[i])
|
||||
{
|
||||
return PartCompare(x1[i], y1[i]);
|
||||
}
|
||||
}
|
||||
if (y1.Length > x1.Length)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if (x1.Length > y1.Length)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return y.CompareTo(x);
|
||||
}
|
||||
}
|
||||
|
||||
private static int PartCompare(string left, string right)
|
||||
{
|
||||
if (!long.TryParse(left, out long x))
|
||||
{
|
||||
return NaturalComparerUtil.CompareNumeric(right, left);
|
||||
}
|
||||
|
||||
if (!long.TryParse(right, out long y))
|
||||
{
|
||||
return NaturalComparerUtil.CompareNumeric(right, left);
|
||||
}
|
||||
|
||||
// If we have an equal part, then make sure that "longer" ones are taken into account
|
||||
if (y.CompareTo(x) == 0)
|
||||
{
|
||||
return right.Length - left.Length;
|
||||
}
|
||||
|
||||
return y.CompareTo(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,7 +66,7 @@ namespace SabreTools.Matching
|
||||
return (false, new List<string>());
|
||||
|
||||
// Initialize the value list
|
||||
List<string> values = new List<string>();
|
||||
List<string> values = [];
|
||||
|
||||
// Loop through all path matches and make sure all pass
|
||||
foreach (var pathMatch in Matchers)
|
||||
|
||||
@@ -2,17 +2,17 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- Assembly Properties -->
|
||||
<TargetFrameworks>net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64;osx-arm64</RuntimeIdentifiers>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Version>1.2.0</Version>
|
||||
<Version>1.3.1</Version>
|
||||
|
||||
<!-- Package Properties -->
|
||||
<Authors>Matt Nadareski</Authors>
|
||||
<Description>Byte array and stream matching library</Description>
|
||||
<Copyright>Copyright (c) Matt Nadareski 2018-2023</Copyright>
|
||||
<Copyright>Copyright (c) Matt Nadareski 2018-2024</Copyright>
|
||||
<PackageProjectUrl>https://github.com/SabreTools/</PackageProjectUrl>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<RepositoryUrl>https://github.com/SabreTools/SabreTools.Matching</RepositoryUrl>
|
||||
@@ -26,6 +26,10 @@
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Support for old .NET versions -->
|
||||
<ItemGroup Condition="$(TargetFramework.StartsWith(`net2`)) OR $(TargetFramework.StartsWith(`net3`))">
|
||||
<PackageReference Include="Net30.LinqBridge" Version="1.3.0" />
|
||||
<PackageReference Include="MinValueTupleBridge" Version="0.2.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="$(TargetFramework.StartsWith(`net4`))">
|
||||
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
|
||||
Reference in New Issue
Block a user