1313
1414namespace MySQLCLRFunctions
1515{
16+ /*
17+ *
18+ * Naming conventions for regex parameters
19+ * - find is for flat string
20+ * - regexmatchpattern when a matching process
21+ * - regexcapturepattern when it has to capture something
22+ * - match is a noun, what was matched to the pattern
23+ */
1624 public static class StringTransform
1725 {
1826 /***************************************************************************************************************************************************************************************************
@@ -51,10 +59,10 @@ private static void FillRowWithCapStrs(Object matchObject, out SqlString match,
5159 *
5260 **************************************************************************************************************************************************************************************/
5361 [ SqlFunction ( DataAccess = DataAccessKind . None , IsDeterministic = true , IsPrecise = true , FillRowMethodName = "FillRowWithStrPieces" ) ]
54- public static IEnumerable Pieces ( String stringtosplitintopieces , String regexsplitterpattern )
62+ public static IEnumerable Pieces ( String stringtosplitintopieces , String regexmatchpattern )
5563 {
5664 returnpieceorderno = 1 ;
57- string [ ] stringpieces = Regex . Split ( stringtosplitintopieces , regexsplitterpattern , RegexOptions . IgnoreCase , TimeSpan . FromSeconds ( 2 ) ) ;
65+ string [ ] stringpieces = Regex . Split ( stringtosplitintopieces , regexmatchpattern , RegexOptions . IgnoreCase , TimeSpan . FromSeconds ( 2 ) ) ;
5866 return stringpieces ;
5967 }
6068
@@ -65,21 +73,111 @@ private static void FillRowWithStrPieces(Object obj, out SqlString piece, out Sq
6573 pieceorderNo = returnpieceorderno ++ ;
6674 }
6775
76+
77+ // Extensions for internal use and simpler Fluent design, but not for SQL to call
78+ internal static string ReplaceMatchExt ( this string input , string regexmatchpattern , string replacement )
79+ {
80+ return ReplaceMatch ( input , regexmatchpattern , replacement ) ;
81+ }
82+
83+ /***************************************************************************************************************************************************************************************************
84+ *
85+ * ReplaceMatch Similar to REPLACE in SQL Server, except it has .NET regex
86+ *
87+ * Note parameter naming convention: find is for flat string, regexmatchpattern when a matching process, regexcapturepattern when it has to capture something
88+ **************************************************************************************************************************************************************************************/
6889 [ SqlFunction ( DataAccess = DataAccessKind . None , IsDeterministic = true , IsPrecise = true ) ]
90+ public static string ReplaceMatch ( string input , string regexmatchpattern , string replacement )
91+ {
92+ return Regex . Replace ( input , regexmatchpattern , replacement ) ;
93+ }
94+
95+ // Extensions for internal use and simpler Fluent design, but not for SQL to call
96+ internal unsafe static string ReplaceRecursiveExt ( this string input , string find , string replacement )
97+ {
98+ return ReplaceRecursive ( input , find , replacement ) ;
99+ }
100+
101+ unsafe public static string ReplaceRecursive ( string input , string find , string replacement )
102+ {
103+ if ( find == replacement ) return input ;
104+ if ( replacement . Contains ( find ) )
105+ {
106+ throw new ArgumentOutOfRangeException ( nameof ( replacement ) , "the replacement string contains the sought string, so recursion would cause a blowup." ) ;
107+ }
108+
109+ if ( find . Length != replacement . Length )
110+ {
111+ StringBuilder sb = new StringBuilder ( input ) ;
112+ while ( true )
113+ {
114+ int formersize = sb . Length ;
115+ sb . Replace ( find , replacement ) ;
116+ int newsize = sb . Length ;
117+ if ( formersize == newsize )
118+ {
119+ return sb . ToString ( ) ;
120+ }
121+ }
122+ }
123+ else if ( find . Length == replacement . Length )
124+ {
125+ int findlen = find . Length ;
126+ var findchars = find . ToCharArray ( ) ;
127+ int len = input . Length ;
128+ fixed ( char * pointer = input )
129+ {
130+ // Add one to each of the characters.
131+ for ( int i = 0 ; i <= len - findlen ; i ++ )
132+ {
133+ int j2 = 0 ;
134+ for ( int j = i ; j < len ; j ++ )
135+ {
136+ if ( pointer [ j + j2 ] != findchars [ j2 ] ) goto outerloop ;
137+ j2 ++ ;
138+ if ( j2 == findlen )
139+ {
140+ // Replace!!!!!!!!
141+
142+ pointer [ j ] = findchars [ 0 ] ;
143+ }
144+ }
145+ outerloop :
146+ ;
147+ }
148+ // Return the mutated string.
149+ return new string ( pointer ) ;
150+ }
151+ }
152+
153+ return input ;
154+ }
155+
69156 /***************************************************************************************************************************************************************************************************
70157 *
71158 * Trim repeating bunches of character off right of string
72159 *
73160 * - Created for trimming "1.3930000000" off floating point number in sql which REFUSES to round.
74161 *
75162 **************************************************************************************************************************************************************************************/
163+ [ SqlFunction ( DataAccess = DataAccessKind . None , IsDeterministic = true , IsPrecise = true ) ]
76164 public static string RTrimChar ( string input , string trimAllOccFromRight )
77165 {
78166 if ( input == null ) return null ;
79167 if ( string . IsNullOrWhiteSpace ( input ) ) return input ;
80168 return input . TrimEnd ( trimAllOccFromRight . ToCharArray ( ) ) ;
81169 }
82170
171+ [ SqlFunction ( DataAccess = DataAccessKind . None , IsDeterministic = true , IsPrecise = true ) ]
172+ public static string RTrimN ( string input , int howmanycharactersoffend )
173+ {
174+ if ( input == null ) return null ;
175+ if ( string . IsNullOrWhiteSpace ( input ) || howmanycharactersoffend == 0 ) return input ;
176+ if ( input . Length <= howmanycharactersoffend ) return string . Empty ;
177+ if ( howmanycharactersoffend < 0 ) throw new ArgumentOutOfRangeException ( nameof ( howmanycharactersoffend ) , howmanycharactersoffend , "Cannot have negate remove characters." ) ;
178+ return input . Substring ( 0 , input . Length - howmanycharactersoffend ) ;
179+ }
180+
83181 [ SqlFunction ( DataAccess = DataAccessKind . None , IsDeterministic = true , IsPrecise = true ) ]
84182 public static string LPad ( string input , int padToLen )
85183 {
@@ -113,15 +211,19 @@ public static string BlankOut(string input, string blankanyofthese, string sep)
113211 }
114212 return input ;
115213 }
214+ /***************************************************************************************************************************************************************************************************
215+ *
216+ * Title Like "UPPER" in SQL Server, as opposed to ToUpper in C#/.NET
217+ *
218+ **************************************************************************************************************************************************************************************/
116219 [ SqlFunction ( DataAccess = DataAccessKind . None , IsDeterministic = true , IsPrecise = true ) ]
117- public static string RemoveSQLServerNameDelimiters ( string input )
220+ public static string Title ( string input )
118221 {
119- if ( string . IsNullOrWhiteSpace ( input ) ) return input ;
120- if ( string . IsNullOrEmpty ( input ) ) return input ;
121-
122- input = input . Trim ( ) . Trim ( new char [ ] { '[' , ']' } ) . Replace ( "]]" , "]" ) ;
123- return input ;
222+ return Regex . Replace ( input , @"\b[a-z]\w+" , delegate ( Match match )
223+ {
224+ string v = match . ToString ( ) ;
225+ return char . ToUpper ( v [ 0 ] ) + v . Substring ( 1 ) ;
226+ } ) ;
124227 }
125-
126228 }
127229}
0 commit comments