From 68b5408b27bc4d0e8bfe0a9867d94f4b6f12f6e5 Mon Sep 17 00:00:00 2001 From: Stephen Cleary Date: Fri, 23 Jun 2023 19:25:40 -0400 Subject: [PATCH] Work in progress --- .../Internals/IStringSplitter.cs | 22 +++++++ .../Internals/ISubstringComparer.cs | 12 ++++ .../Internals/NaturalStringComparison.cs | 64 +++++++++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 src/Nito.Comparers.Core/Internals/IStringSplitter.cs create mode 100644 src/Nito.Comparers.Core/Internals/ISubstringComparer.cs diff --git a/src/Nito.Comparers.Core/Internals/IStringSplitter.cs b/src/Nito.Comparers.Core/Internals/IStringSplitter.cs new file mode 100644 index 0000000..181ee11 --- /dev/null +++ b/src/Nito.Comparers.Core/Internals/IStringSplitter.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Nito.Comparers.Internals +{ + /// + /// + /// + public interface IStringSplitter + { + /// + /// + /// + /// + /// + /// + /// + /// + void MoveNext(string source, ref int offset, out int length, out bool isNumeric); + } +} diff --git a/src/Nito.Comparers.Core/Internals/ISubstringComparer.cs b/src/Nito.Comparers.Core/Internals/ISubstringComparer.cs new file mode 100644 index 0000000..2627659 --- /dev/null +++ b/src/Nito.Comparers.Core/Internals/ISubstringComparer.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Nito.Comparers.Internals +{ + public interface ISubstringComparer + { + int GetHashCode(string source, int offset, int length); + int Compare(string stringA, int offsetA, int lengthA, string stringB, int offsetB, int lengthB); + } +} diff --git a/src/Nito.Comparers.Core/Internals/NaturalStringComparison.cs b/src/Nito.Comparers.Core/Internals/NaturalStringComparison.cs index b941ce2..cdbb993 100644 --- a/src/Nito.Comparers.Core/Internals/NaturalStringComparison.cs +++ b/src/Nito.Comparers.Core/Internals/NaturalStringComparison.cs @@ -180,6 +180,32 @@ public static int Compare(string x, string y, Func _getCultureInfo; + private readonly CompareOptions _compareOptions; + + public DefaultSubstringComparer(StringComparison comparison) + { + _getCultureInfo = comparison switch + { + StringComparison.CurrentCulture => () => CultureInfo.CurrentCulture, + StringComparison.CurrentCultureIgnoreCase => () => CultureInfo.CurrentCulture, + _ => () => CultureInfo.InvariantCulture, + }; + } + + public int Compare(string stringA, int inclusiveStartA, int exclusiveEndA, string stringB, int inclusiveStartB, int exclusiveEndB) + { + throw new NotImplementedException(); + } + + public int GetHashCode(string source, int inclusiveStart, int exclusiveEnd) + { + throw new NotImplementedException(); + } + } + private ref struct SegmentParser { public SegmentParser(string source) @@ -233,5 +259,43 @@ public void ParseNext() static bool IsDigit(char ch) => ch >= '0' && ch <= '9'; } } + + private sealed class DefaultSplitter : IStringSplitter + { + public void MoveNext(string source, ref int offset, out int length, out bool isNumeric) + { + // Prerequisite: start < source.Length + + var index = offset; + isNumeric = IsDigit(source[index++]); + if (isNumeric) + { + // Skip leading zeros, but keep one if that's the only digit. + if (source[offset] == '0') + { + do + { + ++offset; + } while (offset < source.Length && source[offset] == '0'); + if (offset == source.Length || !IsDigit(source[offset])) + --offset; + index = offset + 1; + } + + while (index < source.Length && IsDigit(source[index])) + ++index; + length = index - offset; + } + else + { + index = source.IndexOfAny(Digits, index); + if (index == -1) + index = source.Length; + length = index - offset; + } + + static bool IsDigit(char ch) => ch >= '0' && ch <= '9'; + } + } } }