【问题标题】:Regex to Match Complex Where Clause for Certian Table正则表达式匹配特定表的复杂 Where 子句
【发布时间】: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')

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

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

感谢您的宝贵时间。


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

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 我喜欢这样,请做一个简短的回答,我会接受。我认为这可能会在未来对其他人有所帮助。
  • 附有解释。

标签: c# sql regex where-clause


【解决方案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 的支持不起作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-01-23
  • 1970-01-01
  • 2016-08-11
  • 2021-09-04
  • 2013-08-05
  • 2015-07-08
相关资源
最近更新 更多