@@ -14,7 +14,7 @@ namespace GihanSoft.String;
1414/// <summary>
1515/// Natural Comparer.
1616/// </summary>
17- public class NaturalComparer : IComparer < string ? > , IComparer < ReadOnlyMemory < char > >
17+ public sealed class NaturalComparer : IComparer < string ? > , IComparer < ReadOnlyMemory < char > >
1818{
1919 private readonly StringComparison stringComparison ;
2020
@@ -81,11 +81,34 @@ public static int Compare(ReadOnlySpan<char> x, ReadOnlySpan<char> y, StringComp
8181
8282 if ( char . IsDigit ( xCh ) && char . IsDigit ( yCh ) )
8383 {
84- var xOut = GetNumber ( x . Slice ( i ) , out var xNum ) ;
85- var yOut = GetNumber ( y . Slice ( i ) , out var yNum ) ;
84+ var xOut = GetNumber ( x . Slice ( i ) , out var xNumAsSpan ) ;
85+ var yOut = GetNumber ( y . Slice ( i ) , out var yNumAsSpan ) ;
86+
87+ int compareResult ;
88+
89+ if ( IsUlong ( xNumAsSpan ) && IsUlong ( yNumAsSpan ) )
90+ {
91+ #if NETSTANDARD2_1_OR_GREATER || NET8_0_OR_GREATER
92+ var xNum = ulong . Parse ( xNumAsSpan ) ;
93+ var yNum = ulong . Parse ( yNumAsSpan ) ;
94+ #else
95+ var xNum = ulong . Parse ( xNumAsSpan . ToString ( ) ) ;
96+ var yNum = ulong . Parse ( yNumAsSpan . ToString ( ) ) ;
97+ #endif
98+ compareResult = xNum . CompareTo ( yNum ) ;
99+ }
100+ else
101+ {
102+ #if NETSTANDARD2_1_OR_GREATER || NET8_0_OR_GREATER
103+ var xNum = BigInteger . Parse ( xNumAsSpan ) ;
104+ var yNum = BigInteger . Parse ( yNumAsSpan ) ;
105+ #else
106+ var xNum = BigInteger . Parse ( xNumAsSpan . ToString ( ) ) ;
107+ var yNum = BigInteger . Parse ( yNumAsSpan . ToString ( ) ) ;
108+ #endif
109+ compareResult = xNum . CompareTo ( yNum ) ;
110+ }
86111
87- UnifyNumberTypes ( ref xNum , ref yNum ) ;
88- var compareResult = xNum . CompareTo ( yNum ) ;
89112 if ( compareResult != 0 )
90113 {
91114 return compareResult ;
@@ -97,12 +120,10 @@ public static int Compare(ReadOnlySpan<char> x, ReadOnlySpan<char> y, StringComp
97120 {
98121 return y . Length < x . Length ? - 1 : 1 ; // "033" < "33" === true
99122 }
100- else
101- {
102- x = xOut ;
103- y = yOut ;
104- continue ;
105- }
123+
124+ x = xOut ;
125+ y = yOut ;
126+ continue ;
106127 }
107128
108129 if ( xCh != yCh )
@@ -114,42 +135,47 @@ public static int Compare(ReadOnlySpan<char> x, ReadOnlySpan<char> y, StringComp
114135 return x . Length . CompareTo ( y . Length ) ;
115136 }
116137
117- private static ReadOnlySpan < char > GetNumber ( ReadOnlySpan < char > span , out IComparable number )
138+ private static bool IsUlong ( ReadOnlySpan < char > number )
118139 {
119- var i = 0 ;
120- while ( i < span . Length && char . IsDigit ( span [ i ] ) )
140+ while ( number . Length > 0 && number [ 0 ] == '0' )
121141 {
122- i ++ ;
123- }
124-
125- #if NETSTANDARD2_1_OR_GREATER || NET5_0_OR_GREATER
126- var parseInput = span [ ..i ] ;
127- #else
128- var parseInput = span . Slice ( 0 , i ) . ToString ( ) ;
129- #endif
130-
131- if ( ulong . TryParse ( parseInput , out var ulongResult ) )
132- {
133- number = ulongResult ;
134- }
135- else
136- {
137- number = BigInteger . Parse ( parseInput ) ;
142+ number = number . Slice ( 1 ) ;
138143 }
139144
140- return span . Slice ( i ) ;
145+ // 18446744073709551615
146+ return number switch {
147+ { Length : <= 19 } => true ,
148+ { Length : > 20 } => false ,
149+ [ '1' , < '8' , ..] => true ,
150+ [ '1' , '8' , < '4' , ..] => true ,
151+ [ '1' , '8' , '4' , < '4' , ..] => true ,
152+ [ '1' , '8' , '4' , '4' , < '6' , ..] => true ,
153+ [ '1' , '8' , '4' , '4' , '6' , < '7' , ..] => true ,
154+ [ '1' , '8' , '4' , '4' , '6' , '7' , < '4' , ..] => true ,
155+ [ '1' , '8' , '4' , '4' , '6' , '7' , '4' , < '4' , ..] => true ,
156+ [ '1' , '8' , '4' , '4' , '6' , '7' , '4' , '4' , '0' , < '7' , ..] => true ,
157+ [ '1' , '8' , '4' , '4' , '6' , '7' , '4' , '4' , '0' , '7' , < '3' , ..] => true ,
158+ [ '1' , '8' , '4' , '4' , '6' , '7' , '4' , '4' , '0' , '7' , '3' , < '7' , ..] => true ,
159+ [ '1' , '8' , '4' , '4' , '6' , '7' , '4' , '4' , '0' , '7' , '3' , '7' , '0' , < '9' , ..] => true ,
160+ [ '1' , '8' , '4' , '4' , '6' , '7' , '4' , '4' , '0' , '7' , '3' , '7' , '0' , '9' , < '5' , ..] => true ,
161+ [ '1' , '8' , '4' , '4' , '6' , '7' , '4' , '4' , '0' , '7' , '3' , '7' , '0' , '9' , '5' , < '5' , ..] => true ,
162+ [ '1' , '8' , '4' , '4' , '6' , '7' , '4' , '4' , '0' , '7' , '3' , '7' , '0' , '9' , '5' , '5' , '0' , ..] => true ,
163+ [ '1' , '8' , '4' , '4' , '6' , '7' , '4' , '4' , '0' , '7' , '3' , '7' , '0' , '9' , '5' , '5' , '1' , < '6' , ..] => true ,
164+ [ '1' , '8' , '4' , '4' , '6' , '7' , '4' , '4' , '0' , '7' , '3' , '7' , '0' , '9' , '5' , '5' , '1' , '6' , '0' , ..] => true ,
165+ [ '1' , '8' , '4' , '4' , '6' , '7' , '4' , '4' , '0' , '7' , '3' , '7' , '0' , '9' , '5' , '5' , '1' , '6' , '1' , <= '5' ] => true ,
166+ _ => false
167+ } ;
141168 }
142169
143- private static void UnifyNumberTypes ( ref IComparable x , ref IComparable y )
170+ private static ReadOnlySpan < char > GetNumber ( ReadOnlySpan < char > span , out ReadOnlySpan < char > number )
144171 {
145- if ( x is ulong xLong && y is BigInteger )
172+ var i = 0 ;
173+ while ( i < span . Length && char . IsDigit ( span [ i ] ) )
146174 {
147- x = new BigInteger ( xLong ) ;
175+ i ++ ;
148176 }
149177
150- if ( x is BigInteger && y is ulong yLong )
151- {
152- y = new BigInteger ( yLong ) ;
153- }
178+ number = span . Slice ( 0 , i ) ;
179+ return span . Slice ( i ) ;
154180 }
155- }
181+ }
0 commit comments