如何使用正则表达式解析有限的SQL where子句?
where子句的格式受到限制.它不包含子查询.它仅限于"AND","OR"和"()".
因此,如果给出where子句,我想从中提取部分.
where子句的3个例子:
例如1,我想要"ProjectNumber =?"
例如2,我想要"ProjectNumber =?","severity = 5"
例如3,我想要"ProjectNumber =?","severity = 5","DueDate <(DATETIME('NOW'))"
"?" 表示该值已参数化.
我理解正则表达式不足以解析完整的SQL where子句.
我发现这个"(?<= ^ |\A |(AND | OR))(?:[^'] |'(?:[^'] |'{2})+')*?(?= (AND | OR)| $ |\Z)"但它不适用于3.
编程语言是C#,数据库是SQLite.
ps我是Regex的基本经验.
谢谢.
ps下面是我目前的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'))
Run Code Online (Sandbox Code Playgroud)
小智 7
通过对SQL WHERE谓词施加的限制,可以创建一个正则表达式,在表示类似的结构时提取比较表达式(DATETIME('NOW')).
我将展示和解释的正则表达式要求WHERE谓词在语法上是正确的.如果WHERE谓词有语法错误,则正则表达式可能不匹配或产生垃圾结果.
充满光彩的正则表达式(增加了空格以增强可读性!):
\w[\w\d]* \s*[<>=]{1,2}\s* ( \?|\w[\w\d]*|(\w[\w\d]*)*((?<PR>\()|(?<-PR>\))|[^()])+ )
Run Code Online (Sandbox Code Playgroud)
虽然它肯定不是一个很长的正则表达式,但它仍然很难阅读和理解.因此,让我们解构这个正则表达式并解释它的几个部分.为此,我们将首先看看我们实际想要从WHERE谓词中提取的内容.
我们想要从WHERE谓词中提取的每个表达式都遵循相同的基本模式:
SomeIdentifierWithoutParantheses =|<=|>=|<> SomeOtherThingWithOrWithoutParentheses
Run Code Online (Sandbox Code Playgroud)
这个(a)的高级描述模式足以理解正则表达式需要匹配什么来从WHERE谓词中提取所需的部分.
\w[\w\d]*我们的正则表达式的第一部分与SomeIdentifierWithoutParantheses匹配.这可以是以字母数字字符开头的任何标识符,后跟其他字母数字字符和/或数字.这种标识符的示例是ProjectNumber和My1Ident23.
在正则表达式的第二部分,\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另一个问题,马丁布特内尔已经提供了有关平衡组很好的解释(这个问题的题目是" 什么是正则表达式平衡组? "),我想在这里谁不知道均衡组对他的回答(点击这里导航到马丁的答案).可以在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);
Run Code Online (Sandbox Code Playgroud)
您可以在Regex Storm .NET Regex测试人员的帮助下在线试验正则表达式和不同的输入字符串.