如何使用正则表达式解析有限的SQL where子句?
where子句的格式受到限制。它不包含子查询。它仅限于“AND”,“OR”和“()”。
因此,如果我获得了where子句,我想从中提取部分。
where子句的3个例子:
例如1,我想要“ProjectNumber =?”
例如2,我想要“ProjectNumber =?”,“severity = 5”
例如3,我想要“ProjectNumber =?”,“severity = 5”,“DueDate<(DATETIME('NOW'))”
“?”表示该值已参数化。
我知道正则表达式不足以解析完整的SQL where-clause。
我发现这个“(?< = ^ | \ A |(AND | OR))(?:[^'] |'(?:[^'] |'{2})+')* ?(?=(AND | OR)| $ | \ Z)“但它不适用于3。
编程语言是C#,数据库是SQLite。
P.S。我是Regex的基本经验。
感谢。
P.S。以下是我目前的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'))
答案 0 :(得分:7)
通过对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 。这可以是以字母数字字符开头的任何标识符,后跟其他字母数字字符和/或数字。此类标识符的示例为 ProjectNumber 和 My1Ident23 。
正则表达式\s*[<>=]{1,2}\s*
中的第二部分与比较操作数=
,<=
,>=
和<>
匹配,包括任何空格在比较运算符之前和之后。 (好吧,它也会像=<
那样匹配废话,但是-as在开头说 - 我们假设语法正确的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的另一个问题,MartinBüttner对平衡群体做了很好的解释(问题的主题是“What are regular expression Balancing Groups?”)我想指出任何不了解平衡群体的人他的回答(click here to navigate to Martin's answer)。另一个很好的解释可以在CodeProject上找到。
您会注意到没有任何东西可以处理布尔运算符,例如 AND 或 OR 。这不是必需的,因为这些布尔运算符不是正则表达式匹配的模式的一部分。 (还记得上面关于模式的崇高描述吗?)
如何在C#中使用这样的正则表达式从WHERE谓词中提取所需的部分?
首先,请注意我将继续在正则表达式中使用空格以提高可读性。这需要使用 RegexOptions.IgnorePatternWhitespace 或“(?x)”内联选项进行RegEx初始化。在下面的代码中,我使用前者。
要从WHERE谓词中提取所有部分,将使用RegEx.Matches方法,该方法返回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 tester在线试验正则表达式和不同的输入字符串。