正则表达式匹配特定表的复杂 Where 子句

Posted

技术标签:

【中文标题】正则表达式匹配特定表的复杂 Where 子句【英文标题】:Regex to Match Complex Where Clause for Certian Table 【发布时间】:2018-10-11 13:04:47 【问题描述】:

我有一个程序,它采用受限制的 SQL Server WHERE 子句并删除以 certian 表为目标的 sectiona。这种 where 子句的一个例子是

AND (Util.Source='IP%' AND Util.ReqType = 'IP') AND (Util.Epinum 为空) AND ([Episode].[YN] = 'Y')

我需要删除使用表Episode 的所有查询部分,并考虑() 来括起语句以及字段名称的方括号等。所以要做到这一点我有

private string BuildResourceWhereClauses(string whereClauses, string episodeTable)

    Regex r = new Regex(
        $"AND\\s+\\(*\\[*episodeTable\\]*\\.\\[*\\w+\\]*\\s*(=|<>|<=|>=)(\\s*\\'*(NULL|\\S+|\\((.*?)\\)+)\\'*\\s*\\)*)1",
        RegexOptions.IgnoreCase);

    string tmp = r.Replace(whereClauses, String.Empty).Trim();
    return $" tmp";

这很好,返回

AND (Util.Source='IP%' AND Util.ReqType = 'IP') AND (Util.Epinum 为空)

但是现在,我被要求扩展它,以便我们允许所有 SQL WHERE 子句语法。所以我们现在可以有一个类似

的 where 子句

AND (Util.Source='IP%' AND Util.ReqType = 'IP') AND (Util.Epinum 为空) AND ([Episode].[YN] = 'Y') AND (Episode.Paste = 'Y') AND [Episode].[Source] = '%6' AND [Episode].[TFC] NOT IN ('LWC', 'POD')

说我们要“解析”,所以我把上面的方法修改为

private string BuildResourceWhereClauses(string whereClauses, string episodeTable)

    Regex r = new Regex(
        $"AND\\s+\\(*\\[*episodeTable\\]*\\.\\[*\\w+\\]*\\s*(=|<>|<=|>=|LIKE|IN|NOT IN|IS|BETWEEN\\s+\\w+\\s+AND)(\\s*\\'*(NULL|\\S+|\\((.*?)\\)+)\\'*\\s*\\)*)1",
        RegexOptions.IgnoreCase);

    string tmp = r.Replace(whereClauses, String.Empty).Trim();
    return $" tmp";

使用episodeTable = "Episode"我得到回报

AND (Util.Source='IP%' AND Util.ReqType = 'IP') AND (Util.Epinum 为空)'POD')

此缺失匹配 AND (Episode.Paste = 'Y')AND [Episode].[Source] = '%6'AND [Episode].[TFC] NOT IN ('LWC', 'POD')

    正则表达式有什么问题,如何修改它以返回我想要的?

    与其让这个正则表达式变得复杂,我们可以简化它吗?

感谢您的宝贵时间。


下面的答案去掉了我之前拥有的一些功能(我的错是没有规定我需要保留它!以及是什么让这变得如此困难 - 捕获所有案例“)。所以我需要匹配这个字符串

AND (Util.Source='IP%' AND Util.ReqType = 'IP') AND (Util.Epinum 为空) AND ([Episode].[YN] = 'Y') AND Episode.FRC BETWEEN 10 AND 20 AND Episode.Dt 介于 '2011/02/25' 和 '2011/02/27' 之间 AND (Util.Source='IP%' AND Util.ReqType = 'IP') AND (Util.Epinum 为空) AND ([Episode].[YN] = 'Y' AND Episode.TFC IS NOT LIKE '655r% ') AND (Episode.Paste = 'Y') AND [Episode].[Source] IS NOT LIKE '%6' AND [Episode].[TFC] NOT IN ('LWC', 'POD') AND [Episode].[ TFC] 为空

所以在C#中,我需要下面的代码

string whereClaues = 
    "AND (Util.Source='IP%' AND Util.ReqType = 'IP') AND (Util.Epinum is null) " + 
    "AND ([Episode].[YN] = 'Y') AND Episode.FRC BETWEEN 10 AND 20 AND Episode.Dt between '2011/02/25' and '2011/02/27' " +
    "AND (Util.Source='IP%' AND Util.ReqType = 'IP') AND (Util.Epinum is null) AND ([Episode].[YN] = 'Y' AND Episode.TFC IS NOT LIKE '655r%') " +
    "AND (Episode.Paste = 'Y') AND [Episode].[Source] IS NOT LIKE '%6' AND [Episode].[TFC] NOT IN ('LWC', 'POD') AND [Episode].[TFC] IS NULL";
string tmp = r.Replace(whereClauses, String.Empty).Trim();

tmp作为

AND (Util.Source='IP%' AND Util.ReqType = 'IP') AND (Util.Epinum 为空) AND (Util.Source='IP%' AND Util.ReqType = 'IP') AND (Util.Epinum 为空)

删除所有Episode 子句,包括BETWEEN 语句和IS NOT NULLIS NULL 语句。

AND\s+\(*\[*Episode\]*\.\[*\w+\]*\s*(<>|[><]?=|(?:NOT\s+)?IN|(?:IS\s+)?LIKE|(?:IS\s+NOT\s+)?LIKE|BETWEEN(\s*\'*(\((.*?)\)+|NULL|\S+)\'*\s*\)*)AND)(\s*\'*(\((.*?)\)+|NULL|\S+)\'*\s*\)*)

但这不匹配

Episode.TFC 为空

【问题讨论】:

What is wrong with the regex? 你正在使用正则表达式来修改 SQL,这是一个可怕的 hack。为什么不能只修改 SQL? SQL 来自用户输入。此 where 子句在一个 CTE 查询中用于创建一个 tmp 表,该表随后与另一个连接。我需要去掉 where 子句的 Episode 部分,以便在后续的连接查询中使用。与所有类似的事情一样,我为什么使用这种方法并不总是很清楚。我在这里使用正则表达式,因为它似乎是一种方便的方式来做我想做的事,而无需编写完整的解析器 - 这将是更多的工作。 试试this one @WiktorStribiżew 我喜欢这样,请做一个简短的回答,我会接受。我认为这可能会在未来对其他人有所帮助。 附有解释。 【参考方案1】:

看来您可以通过以下方式扩展您的模式:

$@"AND\s+\(*\[*episodeTable\]*\.\[*\w+\]*\s*(<>|[><]?=|(?:NOT\s+)?IN)(\s*\'*(\((.*?)\)+|NULL|\S+)\'*\s*\)*)"

请参阅regex demo here。

详情

AND - 一个子字符串 \s+ - 1+ 个空格 \(* - 0+ ( 字符 \[* - 0+ [ 字符 Episode - 表名 \]* - 0+ ] 字符 \. - 一个 . 字符 \[* - 0+ [ 字符 \w+ - 1+ 字字符 \]* - 0+ ] 字符 \s* - 0+ 个空格 (&lt;&gt;|[&gt;&lt;]?=|(?:NOT\s+)?IN) - 第 1 组:&lt;&gt;&lt;=&gt;==NOT ININ (\s*\'*(\((.*?)\)+|NULL|\S+)\'*\s*\)*) - 第 2 组: \s* - 0+ 个空格字符 \'* - 0+ ' 字符 (\((.*?)\)+|NULL|\S+) - 第 3 组: \( - 一个( (.*?) - 第 4 组:除换行符之外的任何 0+ 字符尽可能少 \)+ - 1+ ) 字符 | - 或 NULL - NULL 子字符串 | - 或 \S+ - 1+ 非空白字符 \'* - 0+ ' 字符 \s* - 0+ 个空格 \)* - 0+ ) 字符。

【讨论】:

后部疼痛,但我忘记了AND [Episode].[Source] IS LIKE '%6'AND [Episode].[Source] IS NOT LIKE '%6' 之类的部分。此外,在第 3 组中,我们可能有 NOT NULL 您能否就我的更新提出建议 AND\s+\(*\[*Episode\]*\.\[*\w+\]*\s*(&lt;&gt;|[&gt;&lt;]?=|(?:NOT\s+)?IN|(?:IS\s+)?LIKE)(\s*\'*(\((.*?)\)+|IS\s+(?:NOT\s+)?\s+NULL|\S+)\'*\s*\)*) 我尝试添加对 IS NULL 和 IS NOT NULL 的支持不起作用。

以上是关于正则表达式匹配特定表的复杂 Where 子句的主要内容,如果未能解决你的问题,请参考以下文章

MySQL必知应会-第9章-用正则表达式进行搜索

MySql学习笔记 —— 正则表达式的使用

mysql必知必会--用正则表达式 进行搜索

《MySQL必知必会学习笔记》:正则表达式

SQL WHERE 子句的正则表达式

如何修改与 Python 中特定正则表达式匹配的文本?