@@ -19,27 +19,64 @@ public static class StringExtract
1919 private const int CHARACTER_AFTER_MARKER = 1 ;
2020 private const int BACKSET_FOR_ZEROBASED = - 1 ;
2121
22+ /// <summary>
23+ ///
24+ /// IsNullWhiteSpaceOrEmpty - Simple expanding name to avoid constant confusion I have with what this function does.
25+ /// Because most people don't equivocate white space with an empty space, which is the opposite of space. It is non-space.
26+ ///
27+ /// </summary>
28+ /// <param name="input"></param>
29+ /// <returns></returns>
30+ [ SqlFunction ( DataAccess = DataAccessKind . None , IsDeterministic = true , IsPrecise = true ) ]
31+ public static bool IsNullOrWhiteSpaceOrEmpty ( string input )
32+ {
33+ return ( string . IsNullOrWhiteSpace ( input ) ) ;
34+ }
35+
36+ /// <summary>
37+ ///
38+ /// LeftOf - Find the marker, and pull the entire string before that marker first appears, not including that marker.
39+ ///
40+ /// </summary>
41+ /// <param name="input">input possibly containing the marker, at least one instance of that marker.</param>
42+ /// <param name="marker">the string to find.</param>
43+ /// <usecase>null or empty string as a marker returns that input. Think of use case: Running column values through a "LeftOf(',')" Null input should not magically
44+ /// change into a value, i.e., a set of blanks or empty string! By returning input, we say, "Nevermind, just pass thru."</usecase>
45+ /// <returns></returns>
2246 [ SqlFunction ( DataAccess = DataAccessKind . None , IsDeterministic = true , IsPrecise = true ) ]
2347 public static string LeftOf ( string input , string marker )
2448 {
25- if ( string . IsNullOrEmpty ( input ) ) return null ;
49+ if ( IsNullOrWhiteSpaceOrEmpty ( input ) ) return input ;
50+ if ( marker == null ) return null ; // The test is invalid! null is NOT a valid search value, so the result must represent INVALID parameter!
2651
2752 var i = input . IndexOf ( marker ) ;
28- if ( i == NOT_FOUND ) return null ;
53+ if ( i == NOT_FOUND ) return string . Empty ; // Why? So, "LeftOf('x', 'y') is '', because empty string represents NOTHING, where as null represents INVALID INPUTS. This may help chaining functions. A null from a valid test will force any expression to null. Is that what is desired?
54+
2955 return input . Substring ( 0 , i ) ;
3056 }
3157 private static int IndexOfLastChar ( this String str )
3258 {
33- if ( string . IsNullOrWhiteSpace ( str ) ) return NOT_FOUND ;
59+ if ( IsNullOrWhiteSpaceOrEmpty ( str ) ) return NOT_FOUND ;
3460 return str . Length - 1 ;
3561 }
3662
63+ /// <summary>
64+ ///
65+ /// LeftOfNth - Find anything left of the nth found marker - TO THE PREVIOUS MARKER AND NOT INCLUDING THE PREVIOUS MARKER
66+ ///
67+ /// </summary>
68+ /// <param name="input"></param>
69+ /// <param name="marker"></param>
70+ /// <param name="n"></param>
71+ /// <flaws>May need a better name. LeftOfNthFromPrevious?</flaws>
72+ /// <example>LeftOfNth("EDWPROD.UserData.x.y", ".", 2);=> UserData</example>
73+ /// <example>LeftOfNth("EDWPROD.UserData.x.y", ".", 3);=> x</example>
74+ /// <returns></returns>
3775 [ SqlFunction ( DataAccess = DataAccessKind . None , IsDeterministic = true , IsPrecise = true ) ]
3876 public static string LeftOfNth ( string input , string marker , int n )
3977 {
40- if ( string . IsNullOrEmpty ( input ) ) return null ;
41- if ( n < 0 ) throw new ArgumentOutOfRangeException ( nameof ( n ) ) ;
42- if ( n == 0 ) return null ;
78+ if ( string . IsNullOrEmpty ( input ) ) return input ;
79+ if ( n <= 0 ) throw new ArgumentOutOfRangeException ( nameof ( n ) ) ;
4380 var i = input . IndexOf ( marker ) ;
4481 if ( i == NOT_FOUND ) return null ;
4582 if ( n == 1 ) return input . Substring ( 0 , i ) ;
@@ -49,14 +86,29 @@ public static string LeftOfNth(string input, string marker, int n)
4986 if ( i == input . IndexOfLastChar ( ) ) return string . Empty ;
5087 previous_i = i ;
5188 i = input . IndexOf ( marker , i + marker . Length ) ;
52- if ( i == NOT_FOUND ) return null ;
89+ if ( i == NOT_FOUND ) return string . Empty ;
5390 }
5491 if ( i >= input . IndexOfLastChar ( ) ) return string . Empty ;
5592 if ( i == NOT_FOUND ) return null ;
5693 int seglen = i - ( previous_i + marker . Length ) ;
5794 return input . Substring ( previous_i + marker . Length , seglen ) ;
5895 }
5996
97+ /// <summary>
98+ ///
99+ /// LeftMOfNth - Pull m pieces back from the nth finding of a marker.
100+ ///
101+ /// </summary>
102+ /// <param name="input"></param>
103+ /// <param name="marker"></param>
104+ /// <param name="n"></param>
105+ /// <param name="howmany"></param>
106+ /// <example>LeftMOfNth("EDWPROD.UserData.x.y", ".", 1, 1);=> EDWPROD</example>
107+ /// <example>LeftMOfNth("EDWPROD.UserData.x.y", ".", 2, 2);=> EDWPROD.UserData</example>
108+ /// <example>LeftMOfNth("EDWPROD.UserData.x.y", ".", 1, 2);=> </example>
109+ /// <example>LeftMOfNth("EDWPROD.UserData.x.y", ".", 2, 4);=> </example>
110+ /// <bug>LeftMOfNth("..", ".", 1, 1);=> .</bug>
111+ /// <returns></returns>
60112 [ SqlFunction ( DataAccess = DataAccessKind . None , IsDeterministic = true , IsPrecise = true ) ]
61113 public static string LeftMOfNth ( string input , string marker , int n , int howmany )
62114 {
@@ -71,7 +123,7 @@ public static string LeftMOfNth(string input, string marker, int n, int howmany)
71123 if ( i >= input . IndexOfLastChar ( ) ) return string . Empty ;
72124 pointsfound [ j + BACKSET_FOR_ZEROBASED ] = i ;
73125 i = input . IndexOf ( marker , i + marker . Length ) ;
74- if ( i == NOT_FOUND ) return null ;
126+ if ( i == NOT_FOUND ) return string . Empty ;
75127 if ( j == howmany )
76128 {
77129 int startofseg = pointsfound [ j - howmany ] ;
@@ -83,33 +135,41 @@ public static string LeftMOfNth(string input, string marker, int n, int howmany)
83135 return string . Empty ;
84136 }
85137
138+ /// <summary>
139+ ///
140+ /// LeftOfAny - Any of the characters in marker, any string before any of those.
141+ ///
142+ /// </summary>
143+ /// <param name="input"></param>
144+ /// <param name="markerchars"></param>
145+ /// <returns></returns>
86146 [ SqlFunction ( DataAccess = DataAccessKind . None , IsDeterministic = true , IsPrecise = true ) ]
87- public static string LeftOfAny ( string input , string markers )
147+ public static string LeftOfAny ( string input , string markerchars )
88148 {
89- if ( string . IsNullOrEmpty ( input ) ) return null ;
149+ if ( IsNullOrWhiteSpaceOrEmpty ( input ) ) return input ;
90150
91- var i = input . IndexOfAny ( markers . ToCharArray ( ) ) ;
92- if ( i == NOT_FOUND ) return null ;
151+ var i = input . IndexOfAny ( markerchars . ToCharArray ( ) ) ;
152+ if ( i == NOT_FOUND ) return string . Empty ;
93153 return input . Substring ( 0 , i ) ;
94154 }
95155
96156 [ SqlFunction ( DataAccess = DataAccessKind . None , IsDeterministic = true , IsPrecise = true ) ]
97157 public static string RightOf ( string input , string marker )
98158 {
99- if ( string . IsNullOrEmpty ( input ) ) return null ;
159+ if ( string . IsNullOrEmpty ( input ) ) return input ;
100160
101161 var i = input . IndexOf ( marker ) ;
102- if ( i == NOT_FOUND ) return null ;
162+ if ( i == NOT_FOUND ) return string . Empty ;
103163 return input . Substring ( i + marker . Length ) ;
104164 }
105165
106166 [ SqlFunction ( DataAccess = DataAccessKind . None , IsDeterministic = true , IsPrecise = true ) ]
107167 public static string RightOfAny ( string input , string markers )
108168 {
109- if ( string . IsNullOrEmpty ( input ) ) return null ;
169+ if ( IsNullOrWhiteSpaceOrEmpty ( input ) ) return input ;
110170
111171 var i = input . IndexOfAny ( markers . ToCharArray ( ) ) ;
112- if ( i == NOT_FOUND ) return null ;
172+ if ( i == NOT_FOUND ) return string . Empty ;
113173 return input . Substring ( i + 1 ) ;
114174 }
115175
@@ -121,9 +181,11 @@ public static string RightOfAny(string input, string markers)
121181 /// <param name="FullName"></param>
122182 /// <returns></returns>
123183 [ SqlFunction ( DataAccess = DataAccessKind . None , IsDeterministic = true , IsPrecise = true ) ]
124- public static SqlString GetFirstName ( SqlString FullName )
184+ public static string GetFirstName ( string FullName )
125185 {
126- string workingFullName = FullName . ToString ( ) . Trim ( ) ;
186+ if ( IsNullOrWhiteSpaceOrEmpty ( FullName ) ) return FullName ;
187+
188+ string workingFullName = FullName . Trim ( ) ;
127189 string firstName ;
128190
129191 if ( workingFullName . EndsWith ( "(CWF)" ) ) workingFullName = workingFullName . Substring ( 0 , workingFullName . Length - 6 ) . Trim ( ) ;
@@ -148,7 +210,8 @@ public static SqlString GetFirstName(SqlString FullName)
148210 {
149211 firstName = firstName . Substring ( 0 , firstName . Length - 2 ) ;
150212 }
151- return new SqlString ( firstName . Trim ( ) ) ;
213+
214+ return firstName . Trim ( ) ;
152215 }
153216 }
154217}
0 commit comments