I'm looking to convert a SQL like statement on the fly to the equivalent regex i.e.
LIKE '%this%'
LIKE 'Sm_th'
LIKE '[C-P]arsen'
What's the best approach to doing this?
P.S. I'm looking to do this on the .Net Framework (C#).
We use regular expressions to define specific patterns in T-SQL in a LIKE operator and filter results based on specific conditions. We also call these regular expressions as T-SQL RegEx functions. In this article, we will use the term T-SQL RegEx functions for regular expressions.
Regular expressions are a concise and flexible notation for finding and replacing patterns of text. A specific set of regular expressions can be used in the Find what field of the SQL Server Management Studio Find and Replace dialog box.
REGEXP is the operator used when performing regular expression pattern matches. RLIKE is the synonym. It also supports a number of metacharacters which allow more flexibility and control when performing pattern matching. The backslash is used as an escape character.
The following Regex converts an SQL like pattern into a Regex pattern with the help of a MatchEvaluator
delegate. It correctly handles square bracket blocks and escapes special Regex characters.
string regexPattern = "^" + Regex.Replace(
likePattern,
@"[%_]|\[[^]]*\]|[^%_[]+",
match =>
{
if (match.Value == "%")
{
return ".*";
}
if (match.Value == "_")
{
return ".";
}
if (match.Value.StartsWith("[") && match.Value.EndsWith("]"))
{
return match.Value;
}
return Regex.Escape(match.Value);
}) + "$";
In addition to @Nathan-Baulch's solution you can use the code below to also handle the case where a custom escape character has been defined using the LIKE '!%' ESCAPE '!'
syntax.
public Regex ConvertSqlLikeToDotNetRegex(string regex, char? likeEscape = null)
{
var pattern = string.Format(@"
{0}[%_]|
[%_]|
\[[^]]*\]|
[^%_[{0}]+
", likeEscape);
var regexPattern = Regex.Replace(
regex,
pattern,
ConvertWildcardsAndEscapedCharacters,
RegexOptions.IgnorePatternWhitespace);
regexPattern = "^" + regexPattern + "$";
return new Regex(regexPattern,
!m_CaseSensitive ? RegexOptions.IgnoreCase : RegexOptions.None);
}
private string ConvertWildcardsAndEscapedCharacters(Match match)
{
// Wildcards
switch (match.Value)
{
case "%":
return ".*";
case "_":
return ".";
}
// Remove SQL defined escape characters from C# regex
if (StartsWithEscapeCharacter(match.Value, likeEscape))
{
return match.Value.Remove(0, 1);
}
// Pass anything contained in []s straight through
// (These have the same behaviour in SQL LIKE Regex and C# Regex)
if (StartsAndEndsWithSquareBrackets(match.Value))
{
return match.Value;
}
return Regex.Escape(match.Value);
}
private static bool StartsAndEndsWithSquareBrackets(string text)
{
return text.StartsWith("[", StringComparison.Ordinal) &&
text.EndsWith("]", StringComparison.Ordinal);
}
private bool StartsWithEscapeCharacter(string text, char? likeEscape)
{
return (likeEscape != null) &&
text.StartsWith(likeEscape.ToString(), StringComparison.Ordinal);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With