正则表达式解析有限的SQL Where子句

本文关键字:SQL Where 子句 正则表达式 | 更新日期: 2023-09-27 18:15:39

如何使用正则表达式解析有限的SQL where子句?

where-子句的格式受到限制。它不包含子查询。它仅限于"AND"、"OR"answers"()"。

如果给我一个where子句,我想从中提取部分

where-clause的三个例子:

  1. ProjectNumber = ?
  2. ProjectNumber = ?AND严重性= 5
  3. (ProjectNumber = ?AND severity=5) OR DueDate <(DATETIME('现在'))

例如1,我想要"ProjectNumber=?"

例如2,我想要"ProjectNumber =?", "severity = 5"

例如3,我想要"ProjectNumber=?","severity=5","DueDate <"(DATETIME('现在'))"

"?"表示该值是参数化的。

我明白正则表达式不够强大,无法解析完整的SQL where子句。

我发现这种"(& lt; = ^ | ' |和|或 ))(?:[^']|'(?:[^']|'{ 2 })+')*?(?=( 美元和|或)| | ' Z)",但它不工作3 .

编程语言为c#,数据库为SQLite。

注。我对正则表达式有非常基本的经验。

谢谢。

注。下面是我当前的c#代码:

string query = @"(ProjectNumber=? AND severity=5) OR DueDate < (DATETIME('NOW'))";
string pattern = @"(?<=^|'A|(AND|OR))(?:[^']|'(?:[^']|'{2})+')*?(?=(AND|OR)|$|'Z)";
MatchCollection matches = Regex.Matches(query, pattern);
foreach (Match match in matches) 
    Console.WriteLine(match.ToString());
    // currently Console.WriteLine() gives the following:
    // (ProjectNumber=?
    // severity=5)
    //  DueDate < (DATETIME('NOW'))

正则表达式解析有限的SQL Where子句

由于您对SQL WHERE谓词施加了限制,因此可以创建一个正则表达式来提取比较表达式,同时考虑(DATETIME('NOW'))等结构。

我将展示和解释的正则表达式要求WHERE谓词在语法上正确。如果WHERE谓词有语法错误,正则表达式可能不匹配或产生垃圾结果。

正则表达式的全称(添加空格以增强可读性!):

'w['w'd]* 's*[<>=]{1,2}'s* ( '?|'w['w'd]*|('w['w'd]*)*((?<PR>'()|(?<-PR>'))|[^()])+ )

虽然它肯定不是一个很长的正则表达式,但它仍然很难阅读和理解。因此,让我们解构这个正则表达式并解释它的几个部分。要做到这一点,我们将首先看一下我们实际想要从WHERE谓词中提取什么。

我们想从WHERE谓词中提取的每个表达式都遵循相同的基本模式:

SomeIdentifierWithoutParantheses =|<=|>=|<> SomeOtherThingWithOrWithoutParentheses

这个(对a的崇高描述)模式足以理解正则表达式需要匹配什么才能从WHERE谓词中提取所需的部分。

正则表达式中的第一部分'w['w'd]*匹配SomeIdentifierWithoutParantheses。这可以是任何标识符,以字母数字字符开头,后面跟着其他字母数字字符和/或数字。这种标识符的例子有ProjectNumberMy1Ident23

正则表达式的第二部分's*[<>=]{1,2}'s*匹配比较操作数=<=>=<>,包括比较操作符前后的空格。(好吧,它也会匹配像=<这样的废话,但是-正如开头所说-我们假设语法正确的SQL。)

正则表达式的第三部分匹配比较操作符后面的第二个操作数,不可否认这看起来有些笨拙:( '?|'w['w'd]*|('w['w'd]*)*((?<PR>'()|(?<-PR>'))|[^()])+ )。让我们进一步解构正则表达式的这一部分。正如你可能已经注意到的,整个事情是一个有三个可选选项的交替,这将在下面解释。

'?显然匹配单个问号(如"ProjectNumber=?")。'w['w'd]*匹配标识符的方式与第一个操作数的匹配方式相同。

('w['w'd]*)*((?<PR>'()|(?<-PR>'))|[^()])+包含。net中RegEx引擎的特性:平衡组。使用这样的平衡组结构允许正则表达式匹配包含(嵌套)括号( - )组的操作数,如DATETIME('NOW')(DATETIME('NOW'))

对于StackOverflow上的另一个问题,Martin b特纳给出了一个关于平衡组的很好的解释(问题的主题是"什么是正则表达式平衡组?"),我想指出任何不知道平衡组的人他的答案(点击这里导航到Martin的答案)。另一个很好的解释可以在CodeProject上找到。

您将注意到没有任何东西处理布尔运算符,例如AND or 。这是不必要的,因为这些布尔运算符不是正则表达式匹配的模式的一部分。(还记得上面对模式的崇高描述吗?)


如何在c#中使用这样的正则表达式来从WHERE谓词中提取所需的部分?

首先,请注意我将继续在正则表达式中使用空格以提高可读性。这需要使用RegexOptions进行RegEx初始化。IgnorePatternWhitespace或"(?x)"内联选项。在下面的代码中,我使用前者。

要从WHERE谓词中提取所有部分,RegEx。方法,它返回一个Match对象的集合。每个Match对象代表一个提取的部分。

Regex re = new Regex(
    @"'w['w'd]* 's*[<>=]{1,2}'s* ( '?|'w['w'd]*|('w['w'd]*)*((?<PR>'()|(?<-PR>'))|[^()])+ )",
    RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled
);

string wherePredicate =
    "(ProjectNumber=? AND severity=5) OR DueDate < (DATETIME('NOW'))";
    // or use any other WHERE predicate string here...
MatchCollection mc = re.Matches(wherePredicate);
if (mc.Count == 0)
    Console.WriteLine("No matches found.");
else
    foreach (Match m in mc)
        Console.WriteLine("'"{0}'"", m.Value);    


您可以在Regex Storm . net Regex测试器的帮助下在线试验正则表达式和不同的输入字符串。