我正在寻找将类似 SQL 的语句即时转换为等效的正则表达式,即
LIKE '%this%'
LIKE 'Sm_th'
LIKE '[C-P]arsen'
这样做的最佳方法是什么?
PS 我希望在 .Net Framework (C#) 上执行此操作。
下面的 Regex 在MatchEvaluator
委托的帮助下将类似 SQL 的模式转换为 Regex 模式。它正确处理方括号块并转义特殊的正则表达式字符。
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);
}) + "$";
除了@Nathan-Baulch 的解决方案之外,您还可以使用下面的代码来处理使用LIKE '!%' ESCAPE '!'
语法定义了自定义转义字符的情况。
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);
}
从上面的示例中,我会这样攻击它(我笼统地说是因为我不懂 C#):
通过LIKE '...'将其分开,将...部分放入一个数组中。用.*替换未转义的%符号,用. 替换下划线,在这种情况下,[CP]arsen直接转换为正则表达式。
用管道将数组片段重新连接在一起,并将结果包装在括号和标准正则表达式位中。
结果将是:
/^(.*this.*|Sm.th|[C-P]arsen)$/
这里最重要的是要警惕所有可以转义数据的方式,以及哪些通配符转换为哪些正则表达式。
% becomes .*
_ becomes .
我找到了一个名为Regexp::Wildcards的 Perl 模块。您可以尝试移植它或尝试 Perl.NET。我有一种感觉,你也可以自己写一些东西。