Quale codice dovrei utilizzare per convertire al volo un'espressione simile a SQL in una regex?

StackOverflow https://stackoverflow.com/questions/47052

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#).

È stato utile?

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top