Welchen Code würde ich verwenden, um einen SQL-ähnlichen Ausdruck im Handumdrehen in einen regulären Ausdruck umzuwandeln?
Frage
Ich möchte eine SQL-ähnliche Anweisung im Handumdrehen in den entsprechenden regulären Ausdruck konvertieren, d. h.
LIKE '%this%'
LIKE 'Sm_th'
LIKE '[C-P]arsen'
Was ist der beste Ansatz hierfür?
P.S.Ich möchte dies auf dem .Net Framework (C#) tun.
Lösung
Der folgende Regex wandelt mithilfe von a ein SQL-ähnliches Muster in ein Regex-Muster um MatchEvaluator
delegieren.Es verarbeitet eckige Klammerblöcke korrekt und maskiert spezielle Regex-Zeichen.
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);
});
Andere Tipps
Zusätzlich zur Lösung von @Nathan-Baulch können Sie den folgenden Code verwenden, um auch den Fall zu behandeln, in dem ein benutzerdefiniertes Escape-Zeichen mithilfe von definiert wurde 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);
}
Ausgehend von Ihrem obigen Beispiel würde ich es folgendermaßen angreifen (ich spreche allgemein, weil ich C# nicht kenne):
Brechen Sie es auseinander WIE '...', lege das ... Stücke in ein Array.Ersetzen Sie nicht entkommen % Zeichen von .*, unterstrichen durch ., und in diesem Fall die [C-P]arsen wird direkt in Regex übersetzt.
Verbinden Sie die Array-Teile wieder mit einer Pipe und schließen Sie das Ergebnis in Klammern und Standard-Regex-Bits ein.
Das Ergebnis wäre:
/^(.*this.*|Sm.th|[C-P]arsen)$/
Das Wichtigste hierbei ist, dass Sie auf alle Möglichkeiten achten, Daten zu maskieren und welche Platzhalter in welche regulären Ausdrücke übersetzt werden.
% becomes .*
_ becomes .
Ich habe ein Perl-Modul namens gefunden Regexp::Wildcards.Sie können versuchen, es zu portieren oder Perl.NET auszuprobieren.Ich habe das Gefühl, dass Sie auch selbst etwas aufschreiben können.