SQL CLR string functions, including trim, regex replace and more.
using System;
using System.Data.SqlTypes;
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.SqlServer.Server;
namespace SqlClrCommon
{
public partial class SqlFunctions
{
/// <summary>
/// Removes all control characters (non-printable)
/// from the specified string.
/// </summary>
/// <param name="input">
/// The string to remove control characters from.
/// </param>
/// <returns>
/// The string with all non-printable
/// (i.e. control characters) removed.
/// </returns>
/// <remarks>
/// Control characters are those with a Unicode designation
/// of 'Cc' (control), with values in the range U+0000 to U+001F,
/// or U+007F to U+009F.
/// </remarks>
[SqlFunction(
Name = "Clean",
DataAccess = DataAccessKind.None,
SystemDataAccess = SystemDataAccessKind.None)]
public static SqlChars Clean(SqlChars input)
{
if (input.IsNull)
{
return SqlChars.Null;
}
char[] chars = input.Value;
StringBuilder stringBuilder = new StringBuilder(chars.Length);
for (int index = 0; index < chars.Length; ++index)
{
if (!char.IsControl(chars[index]))
{
stringBuilder.Append(chars[index]);
}
}
return new SqlChars(stringBuilder.ToString());
}
/// <summary>
/// Trims leading and trailing whitespace from the
/// specified string.
/// </summary>
/// <param name="input">The string to trim.</param>
/// <returns>The string with leading and trailing
/// whitespace removed.</returns>
[SqlFunction(
Name = "Trim",
DataAccess = DataAccessKind.None,
SystemDataAccess = SystemDataAccessKind.None)]
public static SqlChars Trim(SqlChars input)
{
if (input.IsNull)
{
return SqlChars.Null;
}
return new SqlChars(new string(input.Value).Trim());
}
/// <summary>
/// Replaces all matches of the specified regular
/// expression pattern found in the body with the
/// specified replacementPattern pattern; starting the search at
/// the specified start position.
/// </summary>
/// <param name="input">The input value that will get replaced.</param>
/// <param name="pattern">The regular expression pattern.</param>
/// <param name="replacementPattern">
/// This must be a syntactically-correct regular expression
/// replacement pattern that matches pattern in its references
/// to capture groups, otherwise an exception will be thrown.
/// </param>
/// <param name="start"></param>
/// <returns>The string with the matched pattern replaced.</returns>
/// <remarks>
/// For documentation on replacement patterns
/// see MSDN, NET Framework Regular Expressions, Substitution.
/// </remarks>
/// <example>
/// <code>
/// -- Update a table of names in the format "Lastname, First Names"
/// -- to "First Names Lastname". This illustrates the use of named
/// -- capture groups (lastname, forenames).
/// UPDATE names
/// SET name = dbo.RXREPLACE(name,
/// '^(?<lastname>[A-Za-z\-\']+),\s*(?<forenames>.+)$',
/// '${forenames} ${lastname}', 1);
/// </code>
/// </example>
[SqlFunction(
Name = "RegexReplace",
DataAccess = DataAccessKind.None,
SystemDataAccess = SystemDataAccessKind.None)]
public static SqlChars RegexReplace(
SqlChars input,
SqlChars pattern,
SqlChars replacementPattern,
SqlInt32 start)
{
if (input.IsNull)
{
return SqlChars.Null;
}
if (pattern.IsNull || replacementPattern.IsNull)
{
return input;
}
int startIndex = !start.IsNull ? start.Value - 1 : 0;
if (startIndex >= input.Value.Length)
{
throw new ArgumentException(
string.Format("RegexReplace: Start expected to be between 1 and {0:G} (got {1:G}",
input.Value.Length, startIndex + 1));
}
return new SqlChars(Regex.Replace(
new string(input.Value).Substring(startIndex),
new string(pattern.Value),
new string(replacementPattern.Value))
);
}
}
}