我将使用啥代码将类似 SQL 的表达式即时转换为正则表达式?

Posted

技术标签:

【中文标题】我将使用啥代码将类似 SQL 的表达式即时转换为正则表达式?【英文标题】:What code would I use to convert a SQL like expression to a regex on the fly?我将使用什么代码将类似 SQL 的表达式即时转换为正则表达式? 【发布时间】:2010-09-08 00:06:13 【问题描述】:

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

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

最好的方法是什么?

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

【问题讨论】:

【参考方案1】:

以下 Regex 在 MatchEvaluator 委托的帮助下将类似 SQL 的模式转换为 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);
    ) + "$";

【讨论】:

如果您使用此代码生成的正则表达式,“hello%”将匹配“Say hello”,这是不正确的。 好点@JimBerg,我已经添加了开始/结束锚点。 我使用了您的答案,但对 % 何时位于开头或结尾或两者兼而有之进行了特殊检查。 SQL 表达式与正则表达式相反。如果你想要'%hello%',它只转换为'hello'。 '你好'翻译成'^你好$'。 'hello%' 是 '^hello' 而 '%hello' 是 'hello$'。我不知道是否有人曾经在中间使用 % ,例如 'hello%world' ,它将匹配以 hello 开头并以 world 结尾的任何内容。您的答案似乎确实可以正确处理。很高兴看到您在 9 年后仍然活跃。 :-)【参考方案2】:

除了@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);
    

【讨论】:

【参考方案3】:

从你上面的例子中,我会这样攻击它(我说的是笼统的说法,因为我不懂 C#):

LIKE '...' 将其分开,将 ... 部分放入一个数组中。 将未转义的 % 符号替换为 .*,将下划线替换为 .,在这种情况下,[CP]arsen 直接转换为正则表达式。

用管道将数组片段重新连接在一起,并将结果用括号和标准正则表达式位包裹起来。

结果是:

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

这里最重要的是要警惕所有可以转义数据的方式,以及哪些通配符转换为哪些正则表达式。

% becomes .*
_ becomes .

【讨论】:

需要注意的一点是,如果类似 sql 的模式包含 \,那么您想在正则表达式中转义它。 Regex.Escape 在这里会有所帮助【参考方案4】:

我找到了一个名为 Regexp::Wildcards 的 Perl 模块。您可以尝试移植它或尝试 Perl.NET。我有一种感觉,你也可以自己写一些东西。

【讨论】:

以上是关于我将使用啥代码将类似 SQL 的表达式即时转换为正则表达式?的主要内容,如果未能解决你的问题,请参考以下文章

如果我将字节数组转换为 __attribute__((packed, aligned(2))) 结构会发生啥?

CONVERT是啥函数?

CONVERT是啥意思?

sql语句中的convert是啥意思

如何将表达式树转换为部分 SQL 查询?

我将使用啥 GNU/Linux 命令行工具对文件执行搜索和替换?