我希望将类似 SQL 的语句即时转换为等效的正则表达式,即

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

执行此操作的最佳方法是什么?

附:我希望在 .Net Framework (C#) 上执行此操作。

有帮助吗?

解决方案

下面的正则表达式将类似 SQL 的模式转换为正则表达式模式 MatchEvaluator 代表。它正确处理方括号块并转义特殊的正则表达式字符。

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