11using System ;
2+ using System . Globalization ;
23using System . Linq ;
34using System . Text ;
45using System . Text . RegularExpressions ;
@@ -142,14 +143,9 @@ public static string Truncate(this string input, int maxLength)
142143 /// <returns>Capitalized name</returns>
143144 public static string CapitalizeName ( this string input )
144145 {
145- if ( input == null )
146- {
147- return null ;
148- }
149-
150- if ( input == "" )
146+ if ( string . IsNullOrEmpty ( input ) )
151147 {
152- return "" ;
148+ return input ;
153149 }
154150
155151 var splitedText = string
@@ -225,14 +221,9 @@ public static string CleanSpecialCharacters(this string input, string substitute
225221 /// <returns>New string</returns>
226222 public static string UppercaseFirst ( this string input )
227223 {
228- if ( input == null )
229- {
230- return null ;
231- }
232-
233- if ( input == "" )
224+ if ( string . IsNullOrEmpty ( input ) )
234225 {
235- return "" ;
226+ return input ;
236227 }
237228
238229 var charArray = input . ToCharArray ( ) ;
@@ -247,19 +238,92 @@ public static string UppercaseFirst(this string input)
247238 /// <returns>Text transformed</returns>
248239 public static string LowercaseFirst ( this string input )
249240 {
250- if ( input == null )
251- {
252- return null ;
253- }
254-
255- if ( input == "" )
241+ if ( string . IsNullOrEmpty ( input ) )
256242 {
257- return "" ;
243+ return input ;
258244 }
259245
260246 var charArray = input . ToCharArray ( ) ;
261247 charArray [ 0 ] = char . ToLower ( charArray [ 0 ] ) ;
262248 return new string ( charArray ) ;
263249 }
250+
251+ /// <summary>
252+ /// Convert a text to snake case format
253+ /// </summary>
254+ /// <param name="input">Text to be transformed</param>
255+ /// <returns>Text transformed</returns>
256+ public static string ToSnakeCase ( this string input )
257+ { // Reference1: https://stackoverflow.com/questions/63055621/how-to-convert-camel-case-to-snake-case-with-two-capitals-next-to-each-other
258+ // Reference1: https://github.com/efcore/EFCore.NamingConventions/blob/main/EFCore.NamingConventions/Internal/SnakeCaseNameRewriter.cs
259+ if ( string . IsNullOrEmpty ( input ) )
260+ {
261+ return input ;
262+ }
263+
264+ var builder = new StringBuilder ( input . Length + Math . Min ( 2 , input . Length / 5 ) ) ;
265+ var previousCategory = default ( UnicodeCategory ? ) ;
266+
267+ for ( var currentIndex = 0 ; currentIndex < input . Length ; currentIndex ++ )
268+ {
269+ var currentChar = input [ currentIndex ] ;
270+ if ( currentChar == '_' )
271+ {
272+ builder . Append ( '_' ) ;
273+ previousCategory = null ;
274+ continue ;
275+ }
276+
277+ var currentCategory = char . GetUnicodeCategory ( currentChar ) ;
278+ switch ( currentCategory )
279+ {
280+ case UnicodeCategory . UppercaseLetter :
281+ case UnicodeCategory . TitlecaseLetter :
282+ _snakeCaseHandleUppercaseLetterAndTitlecaseLetter (
283+ input ,
284+ currentIndex ,
285+ previousCategory ,
286+ builder
287+ ) ;
288+
289+ currentChar = char . ToLower ( currentChar , CultureInfo . InvariantCulture ) ;
290+ break ;
291+
292+ case UnicodeCategory . LowercaseLetter :
293+ case UnicodeCategory . DecimalDigitNumber :
294+ if ( previousCategory == UnicodeCategory . SpaceSeparator )
295+ {
296+ builder . Append ( '_' ) ;
297+ }
298+ break ;
299+
300+ default :
301+ if ( previousCategory != null )
302+ {
303+ previousCategory = UnicodeCategory . SpaceSeparator ;
304+ }
305+ continue ;
306+ }
307+
308+ builder . Append ( currentChar ) ;
309+ previousCategory = currentCategory ;
310+ }
311+
312+ return builder . ToString ( ) ;
313+ }
314+
315+ private static void _snakeCaseHandleUppercaseLetterAndTitlecaseLetter ( string input , int currentIndex , UnicodeCategory ? previousCategory , StringBuilder builder )
316+ {
317+ if ( previousCategory == UnicodeCategory . SpaceSeparator ||
318+ previousCategory == UnicodeCategory . LowercaseLetter ||
319+ ( previousCategory != UnicodeCategory . DecimalDigitNumber &&
320+ previousCategory != null &&
321+ currentIndex > 0 &&
322+ currentIndex + 1 < input . Length &&
323+ char . IsLower ( input [ currentIndex + 1 ] ) ) )
324+ {
325+ builder . Append ( '_' ) ;
326+ }
327+ }
264328 }
265329}
0 commit comments