@@ -42,13 +42,78 @@ public static class StringExtensions
4242    /// </summary> 
4343    private  const  DateTimeStyles  DefaultStyles  =  DateTimeStyles . None ; 
4444
45+     /// <summary> 
46+     /// Obtains the zero-based index of the nth occurrence of the specified character in this instance. 
47+     /// If the specified occurrence does not exist, returns -1. 
48+     /// </summary> 
49+     /// <param name="value">The string to search.</param> 
50+     /// <param name="seekValue">The character to seek.</param> 
51+     /// <param name="count">The number of occurrences to skip before returning an index.</param> 
52+     /// <returns> 
53+     /// Returns the zero-based index position of the nth occurrence of <paramref name="seekValue"/>, if found; otherwise, -1. 
54+     /// </returns> 
55+     public  static int  NthIndexOf ( this  string  value ,  char  seekValue ,  int  count ) 
56+     { 
57+         if  ( string . IsNullOrEmpty ( value )  ||  count  <=  0 )  return  - 1 ; 
58+ 
59+         int  occurrences  =  0 ; 
60+ 
61+         for  ( int  i  =  0 ;  i  <  value . Length ;  i ++ ) 
62+         { 
63+             if  ( value [ i ]  !=  seekValue )  continue ; 
64+ 
65+             occurrences ++ ; 
66+ 
67+             if  ( occurrences  !=  count )  continue ; 
68+ 
69+             return  i ; 
70+         } 
71+ 
72+         return  NotFound ; 
73+     } 
74+ 
75+     /// <summary> 
76+     /// Obtains the zero-based index of the nth occurrence of the specified character in this instance. 
77+     /// If the specified occurrence does not exist, returns -1. 
78+     /// </summary> 
79+     /// <param name="value">The string to search.</param> 
80+     /// <param name="seekValue">The substring to seek.</param> 
81+     /// <param name="count">The number of occurrences to skip before returning an index.</param> 
82+     /// <param name="comparison">The comparison that will be used to compare the current value and the seek value.</param> 
83+     /// <returns> 
84+     /// Returns the zero-based index position of the nth occurrence of <paramref name="seekValue"/>, if found; otherwise, -1. 
85+     /// </returns> 
86+     public  static int  NthIndexOf ( this  string  value ,  string  seekValue ,  int  count ,  StringComparison  comparison  =  DefaultComparison ) 
87+     { 
88+         if  ( string . IsNullOrEmpty ( value )  ||  string . IsNullOrEmpty ( seekValue )  ||  count  <=  0 )  return  - 1 ; 
89+ 
90+         int  occurrences  =  0 ; 
91+         int  startIndex  =  0 ; 
92+ 
93+         while  ( true ) 
94+         { 
95+             int  index  =  value . IndexOf ( seekValue ,  startIndex ,  comparison ) ; 
96+ 
97+             if  ( index  ==  - 1 )  return  - 1 ; 
98+ 
99+             occurrences ++ ; 
100+ 
101+             if  ( occurrences  ==  count )  return  index ; 
102+ 
103+             startIndex  =  index  +  seekValue . Length ; 
104+ 
105+             if  ( startIndex  >=  value . Length )  return  NotFound ; 
106+         } 
107+     } 
108+ 
45109    /// <summary> 
46110    /// Repeats the current <see cref="String"/> by the specified number of repetitions. 
47111    /// </summary> 
48112    /// <param name="value">The <see cref="String"/> instance to repeat.</param> 
49113    /// <param name="count">The number of repetitions of the current <see cref="String"/> instance.</param> 
50114    /// <returns>Returns a new <see cref="String"/> instance representing the repetition of the current <see cref="String"/> instance.</returns> 
51-     public  static string  Repeat ( this  string  value ,  int  count )  =>  count  >  0  ?  string . Join ( string . Empty ,  Enumerable . Repeat ( value ,  count ) )  :  string . Empty ; 
115+     public  static string  Repeat ( this  string  value ,  int  count )  => 
116+         count  >  0  ?  string . Join ( string . Empty ,  Enumerable . Repeat ( value ,  count ) )  :  string . Empty ; 
52117
53118    /// <summary> 
54119    /// Obtains a sub-string before the specified index within the current <see cref="String"/> instance. 
@@ -64,7 +129,8 @@ public static class StringExtensions
64129    /// If the default value is <see langword="null"/>, then the current <see cref="String"/> instance will be returned. 
65130    /// </returns> 
66131    // ReSharper disable once HeapView.ObjectAllocation 
67-     private  static string  SubstringBeforeIndex ( this  string  value ,  int  index ,  string ?  defaultValue  =  null )  =>  index  <=  NotFound  ?  defaultValue  ??  value  :  value [ ..index ] ; 
132+     private  static string  SubstringBeforeIndex ( this  string  value ,  int  index ,  string ?  defaultValue  =  null )  => 
133+         index  <=  NotFound  ?  defaultValue  ??  value  :  value [ ..index ] ; 
68134
69135    /// <summary> 
70136    /// Obtains a sub-string after the specified index within the current <see cref="String"/> instance. 
@@ -81,7 +147,8 @@ public static class StringExtensions
81147    /// If the default value is <see langword="null"/>, then the current <see cref="String"/> instance will be returned. 
82148    /// </returns> 
83149    // ReSharper disable once HeapView.ObjectAllocation 
84-     private  static string  SubstringAfterIndex ( this  string  value ,  int  index ,  int  offset ,  string ?  defaultValue  =  null )  =>  index  <=  NotFound  ?  defaultValue  ??  value  :  value [ ( index  +  offset ) ..value . Length ] ; 
150+     private  static string  SubstringAfterIndex ( this  string  value ,  int  index ,  int  offset ,  string ?  defaultValue  =  null )  => 
151+         index  <=  NotFound  ?  defaultValue  ??  value  :  value [ ( index  +  offset ) ..value . Length ] ; 
85152
86153    /// <summary> 
87154    /// Obtains a sub-string before the first occurrence of the specified delimiter within the current <see cref="String"/> instance. 
@@ -235,6 +302,95 @@ public static string SubstringAfterLast(this string value, char delimiter, strin
235302    public  static string  SubstringAfterLast ( this  string  value ,  string  delimiter ,  string ?  defaultValue  =  null ,  StringComparison  comparison  =  DefaultComparison )  => 
236303        value . SubstringAfterIndex ( value . LastIndexOf ( delimiter ,  comparison ) ,  1 ,  defaultValue ) ; 
237304
305+     /// <summary> 
306+     /// Obtains a sub-string before the nth occurrence of the specified character within the current <see cref="String"/> instance. 
307+     /// If the nth occurrence is not found, returns the <paramref name="defaultValue"/> or the entire string if default is null. 
308+     /// </summary> 
309+     /// <param name="value">The current <see cref="String"/> instance from which to obtain a sub-string.</param> 
310+     /// <param name="seekValue">The character to find the nth occurrence of.</param> 
311+     /// <param name="count">The nth occurrence to find.</param> 
312+     /// <param name="defaultValue"> 
313+     /// The <see cref="String"/> value to return if the nth occurrence is not found. 
314+     /// If the default value is <see langword="null"/>, the current <see cref="String"/> instance is returned. 
315+     /// </param> 
316+     /// <returns> 
317+     /// A sub-string before the nth occurrence of <paramref name="seekValue"/> if found; otherwise, 
318+     /// <paramref name="defaultValue"/> or the entire string if default is null. 
319+     /// </returns> 
320+     public  static string  SubstringBeforeNth ( this  string  value ,  char  seekValue ,  int  count ,  string ?  defaultValue  =  null ) 
321+     { 
322+         int  index  =  value . NthIndexOf ( seekValue ,  count ) ; 
323+         return  value . SubstringBeforeIndex ( index ,  defaultValue ) ; 
324+     } 
325+ 
326+     /// <summary> 
327+     /// Obtains a sub-string before the nth occurrence of the specified substring within the current <see cref="String"/> instance. 
328+     /// If the nth occurrence is not found, returns the <paramref name="defaultValue"/> or the entire string if default is null. 
329+     /// </summary> 
330+     /// <param name="value">The current <see cref="String"/> instance from which to obtain a sub-string.</param> 
331+     /// <param name="seekValue">The substring to find the nth occurrence of.</param> 
332+     /// <param name="count">The nth occurrence to find.</param> 
333+     /// <param name="defaultValue"> 
334+     /// The <see cref="String"/> value to return if the nth occurrence is not found. 
335+     /// If the default value is <see langword="null"/>, the current <see cref="String"/> instance is returned. 
336+     /// </param> 
337+     /// <param name="comparison">The comparison that will be used to compare the current value and the seek value.</param> 
338+     /// <returns> 
339+     /// A sub-string before the nth occurrence of <paramref name="seekValue"/> if found; otherwise, 
340+     /// <paramref name="defaultValue"/> or the entire string if default is null. 
341+     /// </returns> 
342+     public  static string  SubstringBeforeNth ( this  string  value ,  string  seekValue ,  int  count ,  string ?  defaultValue  =  null ,  StringComparison  comparison  =  DefaultComparison ) 
343+     { 
344+         int  index  =  value . NthIndexOf ( seekValue ,  count ,  comparison ) ; 
345+         return  value . SubstringBeforeIndex ( index ,  defaultValue ) ; 
346+     } 
347+ 
348+     /// <summary> 
349+     /// Obtains a sub-string after the nth occurrence of the specified character within the current <see cref="String"/> instance. 
350+     /// If the nth occurrence is not found, returns the <paramref name="defaultValue"/> or the entire string if default is null. 
351+     /// </summary> 
352+     /// <param name="value">The current <see cref="String"/> instance from which to obtain a sub-string.</param> 
353+     /// <param name="seekValue">The character to find the nth occurrence of.</param> 
354+     /// <param name="count">The nth occurrence to find.</param> 
355+     /// <param name="defaultValue"> 
356+     /// The <see cref="String"/> value to return if the nth occurrence is not found. 
357+     /// If the default value is <see langword="null"/>, the current <see cref="String"/> instance is returned. 
358+     /// </param> 
359+     /// <returns> 
360+     /// A sub-string after the nth occurrence of <paramref name="seekValue"/> if found; otherwise, 
361+     /// <paramref name="defaultValue"/> or the entire string if default is null. 
362+     /// </returns> 
363+     public  static string  SubstringAfterNth ( this  string  value ,  char  seekValue ,  int  count ,  string ?  defaultValue  =  null ) 
364+     { 
365+         int  index  =  value . NthIndexOf ( seekValue ,  count ) ; 
366+         // Move 1 character after the nth occurrence index. 
367+         return  value . SubstringAfterIndex ( index ,  1 ,  defaultValue ) ; 
368+     } 
369+ 
370+     /// <summary> 
371+     /// Obtains a sub-string after the nth occurrence of the specified substring within the current <see cref="String"/> instance. 
372+     /// If the nth occurrence is not found, returns the <paramref name="defaultValue"/> or the entire string if default is null. 
373+     /// </summary> 
374+     /// <param name="value">The current <see cref="String"/> instance from which to obtain a sub-string.</param> 
375+     /// <param name="seekValue">The substring to find the nth occurrence of.</param> 
376+     /// <param name="count">The nth occurrence to find.</param> 
377+     /// <param name="defaultValue"> 
378+     /// The <see cref="String"/> value to return if the nth occurrence is not found. 
379+     /// If the default value is <see langword="null"/>, the current <see cref="String"/> instance is returned. 
380+     /// </param> 
381+     /// <param name="comparison">The comparison that will be used to compare the current value and the seek value.</param> 
382+     /// <returns> 
383+     /// A sub-string after the nth occurrence of <paramref name="seekValue"/> if found; otherwise, 
384+     /// <paramref name="defaultValue"/> or the entire string if default is null. 
385+     /// </returns> 
386+     public  static string  SubstringAfterNth ( this  string  value ,  string  seekValue ,  int  count ,  string ?  defaultValue  =  null ,  StringComparison  comparison  =  DefaultComparison ) 
387+     { 
388+         int  index  =  value . NthIndexOf ( seekValue ,  count ,  comparison ) ; 
389+         // Move by the length of the found substring after the nth occurrence index. 
390+         int  offset  =  ( index  !=  NotFound  &&  ! string . IsNullOrEmpty ( seekValue ) )  ?  seekValue . Length  :  0 ; 
391+         return  value . SubstringAfterIndex ( index ,  offset ,  defaultValue ) ; 
392+     } 
393+ 
238394    /// <summary> 
239395    /// Converts the current <see cref="String"/> instance into a new <see cref="T:Byte[]"/> instance. 
240396    /// </summary> 
@@ -336,7 +492,8 @@ public static bool TryCopyTo(this string value, Span<char> destination, out int
336492    /// <param name="before">The <see cref="Char"/> that should precede the current <see cref="String"/> instance.</param> 
337493    /// <param name="after">The <see cref="Char"/> that should succeed the current <see cref="String"/> instance.</param> 
338494    /// <returns>Returns a new <see cref="String"/> instance representing the current <see cref="String"/> instance, wrapped between the specified before and after <see cref="Char"/> instances.</returns> 
339-     public  static string  Wrap ( this  string  value ,  char  before ,  char  after )  =>  string . Concat ( before . ToString ( ) ,  value ,  after . ToString ( ) ) ; 
495+     public  static string  Wrap ( this  string  value ,  char  before ,  char  after )  => 
496+         string . Concat ( before . ToString ( ) ,  value ,  after . ToString ( ) ) ; 
340497
341498    /// <summary> 
342499    /// Wraps the current <see cref="String"/> instance between the specified before and after <see cref="String"/> instances. 
@@ -345,5 +502,6 @@ public static bool TryCopyTo(this string value, Span<char> destination, out int
345502    /// <param name="before">The <see cref="String"/> that should precede the current <see cref="String"/> instance.</param> 
346503    /// <param name="after">The <see cref="String"/> that should succeed the current <see cref="String"/> instance.</param> 
347504    /// <returns>Returns a new <see cref="String"/> instance representing the current <see cref="String"/> instance, wrapped between the specified before and after <see cref="String"/> instances.</returns> 
348-     public  static string  Wrap ( this  string  value ,  string  before ,  string  after )  =>  string . Concat ( before ,  value ,  after ) ; 
505+     public  static string  Wrap ( this  string  value ,  string  before ,  string  after )  => 
506+         string . Concat ( before ,  value ,  after ) ; 
349507} 
0 commit comments