Quale codice dovrei utilizzare per convertire al volo un'espressione simile a SQL in una regex?
Domanda
Sto cercando di convertire al volo un'istruzione simile a SQL nella regex equivalente, ad es.
LIKE '%this%'
LIKE 'Sm_th'
LIKE '[C-P]arsen'
Qual è l'approccio migliore per farlo?
PSSto cercando di farlo su .Net Framework (C#).
Soluzione
Il seguente Regex converte un modello simile a SQL in un modello Regex con l'aiuto di a MatchEvaluator
delegare.Gestisce correttamente i blocchi di parentesi quadre ed esegue l'escape dei caratteri Regex speciali.
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);
});
Altri suggerimenti
Oltre alla soluzione di @ Nathan-Baulch puoi utilizzare il codice seguente per gestire anche il caso in cui è stato definito un carattere di escape personalizzato utilizzando il comando LIKE '!%' ESCAPE '!'
sintassi.
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);
}
Dal tuo esempio sopra, lo attaccherei in questo modo (parlo in termini generali perché non conosco C#):
Spezzalo COME '...', metti il ... pezzi in un array.Sostituisci senza caratteri di escape % segni di .*, sottolineato da ., e in questo caso il [C-P]arsen si traduce direttamente in regex.
Unisci nuovamente i pezzi dell'array con una pipe e racchiudi il risultato tra parentesi e bit regex standard.
Il risultato sarebbe:
/^(.*this.*|Sm.th|[C-P]arsen)$/
La cosa più importante qui è prestare attenzione a tutti i modi in cui è possibile sfuggire ai dati e a quali caratteri jolly si traducono in quali espressioni regolari.
% becomes .*
_ becomes .
Ho trovato un modulo Perl chiamato Regexp::Caratteri jolly.Puoi provare a portarlo o provare Perl.NET.Ho la sensazione che anche tu potresti scrivere qualcosa da solo.