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';
+ }
+ }
}
}