首页 > 编程 > Regex > 正文

应该如何构造复杂的正则表达式

2020-03-22 19:03:34
字体:
来源:转载
供稿:网友
文题本来是《如何构造复杂的html' target='_blank'>正则表达式》,但是觉得有些歧义,就感觉正则式本来很简单,我在教人如何将它小事化大一样。正好相反,我的本意是说,即使复杂的正则式也不怕,找出合适的方法,将其构造出来。

避重就轻

Snopo给出的文本是这样的:or and name='zhangsan' and id=001 or age 20 or area='%renmin%' and like,问,如何提取其中正确的SQL查询语句。

简要分析可知,中间部分是合乎要求的,只是两端的有若干个like, or, and。构造能够解析合乎SQL语法的查询语句的正则表达式,应该是比较复杂的。可是,对于具体的问题,也可以更简单。上述的不良构的SQL语句,应该是使用程序自动生成的,它的两端会有一些不符合题意的文本。只要将这些文本去除就可以了。

于是,我写出了正则表达式:s/^(?:(?:or|and|like)/s*)+|/s*(?:(?:or|and|like)/s*)+$//mi;,这样就把多行字串首尾的like, or, and以及可能的空白字符全部去掉了,剩下的内容即为所求。

分而治之

答案发过去之后,Snopo显然不是很满意这种“偷懒”的办法。他继续问道,能否写出正则式,用来匹配合符SQL语法要求的条件查询语句?(只考虑where部分即可,不必写完整的select。)

的确,从快速解决问题的角度来说,只要能够行之有效地解决,用什么办法都可以;不过从学习知识的角度来说,不避重就轻,而是刨根问底,才是正途。既如此,就看一下如何使用正则,将该SQL查询语句解决掉。

最简单的查询语句,应该是真假判断,即 where 1; where True; where false,等等。 这样的语句使用正则式,直接/(?:-?/d+|True|False)/i。

稍复杂些的单条语句,可以是左右比较,即

复制代码 代码如下:
name like 'zhang%', 或 age 25 ,或 work in ('it', 'hr', 'R&D')

。将其简单化,结构就变为A OP B。其中A代表变量,OP代表比较操作符,B代表值。

A: 最简单的A,应该是/w+。考虑到实际情况,变量包含点号或脱字符,例如`table.salary`,可以记为/[/w.`]+/。这是比较笼统的细化。如果要求比较苛刻,还可以做到让脱字符同时在左右两边出现(条件判断)。
OP: Where 常用的几种关系比较为:=, , , , =, =, Between, Like, in。使用简单的正则描述之,成为:/(?:[ =]{1,2}|Between|Like|In)/i。
B: B 的情况又可分为3种:变量,数字,字符串,列表。为简单起见,这里就不考虑算术表达式了。

变量的话,直接延用A的定义即可。不赘述。
数字:使用//d+/来定义。不考虑小数和负数了。

字符串:包括单引号字串和双引号字串。中间可以包括被转义的引号。我写了一个符合这一要求的引号字串正则表达式,形如:/(['"])(?://['"]|[^//1])*?/1/。不过,由于它只是庞大机器的一个零件,这样写的风险是极其大的。首先,它使用了反向引用;其次,该反向引用使用了全局的反向引用编号。我写了自动生成全局编号的函数,来解决这一问题。不过,这里谈细节是不是太深入了。应该先谈框架,再说细节才对。不应该一入手就陷进细节的汪洋大海。

列表:列表是形如(1, 3 , 4) 或 ("it", "hr", "r&d")之类的东东,它由简单变量以逗号相连,两边加上括号组成。列表的单项以I表示,它代表 数字|字符串。此时,列表就变为://(I(?:,I)*?/)/。它表示,左括号,一个I,一系列由逗号、I组成的其它列表项(0个或多个),右括号。简单起见没有考虑空白字符。
至此,可以总结出单条语句的正则框架:S =~ /A OP B/i。S在此代表单条语句。
更为复杂的是多条语句,可以由单条语句组成,中间使用 and 或 or 连接。合理地构造单条语句,将其稳定地编制为多条语句,任务就完成了。

沿用上面的示例,以S代表单条语句,那么复合语句C就是 C =~ S(?:(?:or|and) S)*?/。至此,一个初具规模的条件语句解析器就诞生了。下面以python为例,一步一步实现出来。

Python实现
重申一句:虽然给出了实现,但是仍请注重思路,忽略代码。
复制代码 代码如下:
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
#author: rex
#blog: http://iregex.org
#filename test.py
#created: 2010-08-06 17:12

#generage quoted string;
#including ' and " string
#allow /' and /" inside
index=0
def gen_quote_str():

global index
index+=1
char=chr(96+index)
return r"""(?P quote_%s ['"])(?://['"]|[^'"])*?(?P=quote_%s)"""% (char, char)


#simple variable
def a():
return r'[/w.`]+'

#operators
def op():
return r'(?:[ =]{1,2}|Between|Like|In)'


#list item within (,)

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表