11using System ;
22using System . Collections . Generic ;
3+ using System . Collections . Immutable ;
34using System . Diagnostics ;
45using System . Diagnostics . Contracts ;
56using System . Linq ;
@@ -144,7 +145,7 @@ public static ReadOnlySpan<char> FirstSplit(this ReadOnlySpan<char> source,
144145 }
145146
146147 var i = source . IndexOf ( splitSequence , comparisonType ) ;
147- return FirstSplitSpan ( source , i , 1 , out nextIndex ) ;
148+ return FirstSplitSpan ( source , i , splitSequence . Length , out nextIndex ) ;
148149 }
149150
150151#pragma warning disable CS8524 // The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value.
@@ -198,19 +199,18 @@ IEnumerable<string> SplitAsEnumerableCoreOmitEmpty()
198199 }
199200 }
200201
201-
202202 /// <summary>
203203 /// Enumerates a string by segments that are separated by the split character.
204204 /// </summary>
205205 /// <param name="source">The source characters to look through.</param>
206206 /// <param name="splitSequence">The sequence to find.</param>
207- /// <param name="comparisonType">The string comparison type to use.</param>
208207 /// <param name="options">Can specify to omit empty entries.</param>
208+ /// <param name="comparisonType">The string comparison type to use.</param>
209209 /// <returns>The portion of the source up to and excluding the sequence searched for.</returns>
210210 public static IEnumerable < string > SplitToEnumerable ( this string source ,
211211 string splitSequence ,
212- StringComparison comparisonType = StringComparison . Ordinal ,
213- StringSplitOptions options = StringSplitOptions . None )
212+ StringSplitOptions options = StringSplitOptions . None ,
213+ StringComparison comparisonType = StringComparison . Ordinal )
214214 {
215215 if ( source is null ) throw new ArgumentNullException ( nameof ( source ) ) ;
216216 if ( splitSequence is null ) throw new ArgumentNullException ( nameof ( splitSequence ) ) ;
@@ -301,8 +301,8 @@ IEnumerable<ReadOnlyMemory<char>> SplitAsMemoryOmitEmpty()
301301 /// <inheritdoc cref="SplitToEnumerable(string, string, StringComparison, StringSplitOptions)"/>
302302 public static IEnumerable < ReadOnlyMemory < char > > SplitAsMemory ( this string source ,
303303 string splitSequence ,
304- StringComparison comparisonType = StringComparison . Ordinal ,
305- StringSplitOptions options = StringSplitOptions . None )
304+ StringSplitOptions options = StringSplitOptions . None ,
305+ StringComparison comparisonType = StringComparison . Ordinal )
306306 {
307307 if ( source is null ) throw new ArgumentNullException ( nameof ( source ) ) ;
308308 if ( splitSequence is null ) throw new ArgumentNullException ( nameof ( splitSequence ) ) ;
@@ -324,9 +324,10 @@ public static IEnumerable<ReadOnlyMemory<char>> SplitAsMemory(this string source
324324 IEnumerable < ReadOnlyMemory < char > > SplitAsMemoryCore ( )
325325 {
326326 var startIndex = 0 ;
327+ var splitLen = splitSequence . Length ;
327328 do
328329 {
329- yield return FirstSplitMemory ( source , startIndex , source . IndexOf ( splitSequence , startIndex , comparisonType ) , 1 , out var nextIndex ) ;
330+ yield return FirstSplitMemory ( source , startIndex , source . IndexOf ( splitSequence , startIndex , comparisonType ) , splitLen , out var nextIndex ) ;
330331 startIndex = nextIndex ;
331332 }
332333 while ( startIndex != - 1 ) ;
@@ -335,16 +336,113 @@ IEnumerable<ReadOnlyMemory<char>> SplitAsMemoryCore()
335336 IEnumerable < ReadOnlyMemory < char > > SplitAsMemoryOmitEmpty ( )
336337 {
337338 var startIndex = 0 ;
339+ var splitLen = splitSequence . Length ;
338340 do
339341 {
340- var result = FirstSplitMemory ( source , startIndex , source . IndexOf ( splitSequence , startIndex , comparisonType ) , 1 , out var nextIndex ) ;
342+ var result = FirstSplitMemory ( source , startIndex , source . IndexOf ( splitSequence , startIndex , comparisonType ) , splitLen , out var nextIndex ) ;
341343 if ( result . Length != 0 ) yield return result ;
342344 startIndex = nextIndex ;
343345 }
344346 while ( startIndex != - 1 ) ;
345347 }
346348 }
349+
347350#pragma warning restore CS8524 // The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value.
348351
352+ static readonly ImmutableArray < string > SingleEmpty = ImmutableArray . Create ( string . Empty ) ;
353+
354+ /// <summary>
355+ /// Splits a sequence of characters into strings using the character provided.
356+ /// </summary>
357+ /// <param name="source">The source string to split up.</param>
358+ /// <param name="splitCharacter">The character to split by.</param>
359+ /// <param name="options">Can specify to omit empty entries.</param>
360+ /// <returns>The resultant list of string segments.</returns>
361+ public static IReadOnlyList < string > Split ( this ReadOnlySpan < char > source ,
362+ char splitCharacter ,
363+ StringSplitOptions options = StringSplitOptions . None )
364+ {
365+ switch ( options )
366+ {
367+ case StringSplitOptions . None when source . Length == 0 :
368+ return SingleEmpty ;
369+
370+ case StringSplitOptions . RemoveEmptyEntries when source . Length == 0 :
371+ return ImmutableArray < string > . Empty ;
372+
373+ case StringSplitOptions . RemoveEmptyEntries :
374+ {
375+ Debug . Assert ( ! source . IsEmpty ) ;
376+ var list = new List < string > ( ) ;
377+
378+ loop :
379+ var result = source . FirstSplit ( splitCharacter , out var nextIndex ) ;
380+ if ( ! result . IsEmpty ) list . Add ( result . ToString ( ) ) ;
381+ if ( nextIndex == - 1 ) return list ;
382+ source = source . Slice ( nextIndex ) ;
383+ goto loop ;
384+ }
385+
386+ default :
387+ {
388+ Debug . Assert ( ! source . IsEmpty ) ;
389+ var list = new List < string > ( ) ;
390+ loop :
391+ var result = source . FirstSplit ( splitCharacter , out var nextIndex ) ;
392+ list . Add ( result . IsEmpty ? string . Empty : result . ToString ( ) ) ;
393+ if ( nextIndex == - 1 ) return list ;
394+ source = source . Slice ( nextIndex ) ;
395+ goto loop ;
396+ }
397+ }
398+ }
399+
400+ /// <summary>
401+ /// Splits a sequence of characters into strings using the character sequence provided.
402+ /// </summary>
403+ /// <param name="source">The source string to split up.</param>
404+ /// <param name="splitSequence">The sequence to split by.</param>
405+ /// <param name="options">Can specify to omit empty entries.</param>
406+ /// <param name="comparisonType">The optional comparsion type.</param>
407+ /// <returns>The resultant list of string segments.</returns>
408+ public static IReadOnlyList < string > Split ( this ReadOnlySpan < char > source ,
409+ in ReadOnlySpan < char > splitSequence ,
410+ StringSplitOptions options = StringSplitOptions . None ,
411+ StringComparison comparisonType = StringComparison . Ordinal )
412+ {
413+ switch ( options )
414+ {
415+ case StringSplitOptions . None when source . IsEmpty :
416+ return SingleEmpty ;
417+
418+ case StringSplitOptions . RemoveEmptyEntries when source . IsEmpty :
419+ return ImmutableArray < string > . Empty ;
420+
421+ case StringSplitOptions . RemoveEmptyEntries :
422+ {
423+ Debug . Assert ( ! source . IsEmpty ) ;
424+ var list = new List < string > ( ) ;
425+
426+ loop :
427+ var result = source . FirstSplit ( splitSequence , out var nextIndex , comparisonType ) ;
428+ if ( ! result . IsEmpty ) list . Add ( result . ToString ( ) ) ;
429+ if ( nextIndex == - 1 ) return list ;
430+ source = source . Slice ( nextIndex ) ;
431+ goto loop ;
432+ }
433+
434+ default :
435+ {
436+ Debug . Assert ( ! source . IsEmpty ) ;
437+ var list = new List < string > ( ) ;
438+ loop :
439+ var result = source . FirstSplit ( splitSequence , out var nextIndex , comparisonType ) ;
440+ list . Add ( result . IsEmpty ? string . Empty : result . ToString ( ) ) ;
441+ if ( nextIndex == - 1 ) return list ;
442+ source = source . Slice ( nextIndex ) ;
443+ goto loop ;
444+ }
445+ }
446+ }
349447 }
350448}
0 commit comments