その場でSQLのようなステートメントを同等の正規表現に変換しようとしています。
LIKE '%this%'
LIKE 'Sm_th'
LIKE '[C-P]arsen'
これを行うための最良のアプローチは何ですか?
PS私は.Net Framework(C#)でこれをやろうとしています。
MatchEvaluator
次の正規表現は、デリゲートの助けを借りて、SQL のようなパターンを正規表現パターンに変換します。角括弧ブロックを正しく処理し、特殊な正規表現文字をエスケープします。
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);
}) + "$";
LIKE '!%' ESCAPE '!'
@ Nathan-Baulchのソリューションに加えて、以下のコードを使用して、構文を使用してカスタムエスケープ文字が定義されている場合も処理できます。
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 を試すことができます。あなたも自分で何かを書き留めることができると思います。