SQL과 같은 표현식을 즉시 정규식으로 변환하려면 어떤 코드를 사용해야 합니까?

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

문제

SQL과 같은 문을 즉석에서 동등한 정규식으로 변환하려고 합니다.

LIKE '%this%'
LIKE 'Sm_th'
LIKE '[C-P]arsen'

이 작업을 수행하는 가장 좋은 방법은 무엇입니까?

추신저는 .Net Framework(C#)에서 이 작업을 수행하려고 합니다.

도움이 되었습니까?

해결책

다음 Regex는 SQL과 유사한 패턴을 다음의 도움으로 Regex 패턴으로 변환합니다. MatchEvaluator 대리자.대괄호 블록을 올바르게 처리하고 특수 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#을 모르기 때문에 일반적인 용어로 말합니다).

그것을 분해하여 좋다 '...', 넣어 ... 조각을 배열로 만듭니다.이스케이프되지 않은 바꾸기 % 표지판 .*, 밑줄은 .로 표시되며, 이 경우에는 [C-P]아르센 정규식으로 직접 변환됩니다.

배열 조각을 파이프로 다시 결합하고 결과를 괄호와 표준 정규식 비트로 묶습니다.

결과는 다음과 같습니다.

/^(.*this.*|Sm.th|[C-P]arsen)$/

여기서 가장 중요한 것은 데이터를 이스케이프할 수 있는 모든 방법과 어떤 와일드카드가 어떤 정규식으로 변환되는지 주의하는 것입니다.

% becomes .*
_ becomes .

Perl 모듈을 찾았습니다. 정규식::와일드카드.이식을 시도하거나 Perl.NET을 사용해 볼 수 있습니다.당신도 스스로 뭔가를 쓸 수 있을 것 같은 느낌이 듭니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top