题目本来是《如何构造复杂的正则表达式》,但是感觉有点暧昧的时候就觉得正则表达式很简单,在教人怎么把它变小。相反,我的本意是说,即使是复杂的正则表达式也不怕。找出合适的方法并构建它们。Snopo给出的文本如下:or和name=' zhangshan '和id=001 or age20 or area='% renmin% '等,询问如何提取正确的SQL查询语句。简单分析一下,中间部分还算满意,但是两端有几个像,或者,和。构建能够根据SQL语法解析查询语句的正则表达式应该很复杂。但是,对于具体问题,也可以简单一些。以上格式不良的SQL语句应该是使用程序自动生成的,两端会有一些不符合题意的文字。去掉文字就行了。所以我写了一个正则表达式:s/(?(?or |和|like)s*) |s*(吗?(?or |和| like) s *)$//mi;这样,多行字符串开头和结尾的所有like、or和可能的空白字符都会被删除,剩下的就是您想要的了。分而治之的答案发出后,Snopo显然对这种“偷懒”的方法不满意。他继续问,能不能写一个正则表达式来匹配符合SQL语法要求的条件查询语句?(只考虑where部分,不必编写完整的select。的确,从快速解决问题的角度来看,只要能有效解决,任何方法都可以用;但是,从学习知识的角度来看,这是一条正确的触底之路,而不是避重就轻。在这种情况下,让我们看看如何使用正则化来解决这个SQL查询语句。最简单的查询语句应该是真假判断,即其中1;真实的地方;真的,在哪里等。这样的语句使用正则表达式,直接/(?-? d |真|假)/i .稍微复杂一点的单条语句可以左右比较,也就是复制的代码如下:name喜欢' zhang% ',或者age25,或者work in ('it ',' hr ',' RD ')。为了简化它,结构变成了A OP B.其中a代表变量,OP代表比较运算符,b代表值。A :最简单的a应该是 w .考虑到实际情况,变量中包含一个点或插入符号,比如table.salary ',可以写成/[w.`]/。这是一个更一般的细化。如果要求苛刻,也可以让脱字符号同时出现在两边(条件判断)。OP:其中常用的关系是=,=,=,介于,类似,在。使用简单的常规描述,变成:/(?[=]{1,2 } |介于|相似|在)/i .B:b可以分为三种类型:变量、数字、字符串和列表。为了简单起见,这里不考虑算术表达式。变量,一个的定义可以直接扩展。不要重复。数字:使用/ d/来定义。忘记小数和负数。字符串:包括单引号字符串和双引号字符串。您可以在中间包含转义引号。我写了一个符合这个要求的引号字符串正则表达式,就像:/([''])(?\['']|[^\1])*?1/。然而,由于它只是一个巨大机器的一部分,这样写的风险是极其巨大的。首先,它使用反向引用。其次,反向引用使用全局反向引用号。我写了一个自动生成全局数字的函数来解决这个问题。不过这里谈细节也不算太深。先讲框架,再讲细节。你不应该一开始就陷入细节的海洋。list:list类似于(1,3,4)或(' it ',' hr ',' rd '),由两边带括号的逗号连接的简单变量组成。列表中的单个项目由I表示,I表示数字|字符串。此时,列表变成:/(我(?我)*?)/。它的意思是,左括号,一个I,一系列由逗号和I组成的其他列表项(0或更多),以及右括号。为了简单起见,不考虑空白字符。至此,我们可以总结出单个语句的正则框架:S=~ /A OP B/i.s在这里只代表一种说法。更复杂的是多条语句,可以由一条语句组成,中间用和或连接。
合理地构造单条语句,将其稳定地编制为多条语句,任务就完成了。沿用上面的示例,以S代表单条语句,那么复合语句C就是C=~ S(?(?or|and) S)*?/。至此,一个初具规模的条件语句解析器就诞生了。下面以大蟒为例,一步一步实现出来Python。实现重申一句:虽然给出了实现,但是仍请注重思路,忽略代码。复制代码代码如下: #!/usr/bin/python #-*-编码: utf-8-*-# #作者: rex #博客: http://iregex.org #文件名测试。py #创建d : 2010-08-06 17:12 # generage引用字符串;#包括'和字符串#allow和内部索引=0 def gen _ quote _ str():全局索引索引=1 char=chr(96索引)返回r ' '(?Pquote_%s[''])(?\['']|[^''])*?(?P=quote_%s)'''% (char,char)#简单变量def a(:)返回r '[ w `] ' #运算符def op():返回r '(?[=]{1,2 } | Between | Like | In)' #列表项In(,#eg: 'a ',23,a.b,' asdfasdf ' aasdf ' def项(): return r '(?%s|%s)' % (a(),gen _ quote _ str())#一个复杂列表,像#eg: (23,24,44),(' regex ',' is ',' good') def items():返回r ' ' ( s * % s(?s* %s)* s* )''' % (item(),item())#简单比较#eg: a=15,b23 def s():返回% s s * % s s *(什么? w | % s | % s)' ' ' ' %(a(),op(),gen_quote_str(),items())#复杂比较#名称如张% '和23岁和工作在(' hr ',' it ',' rd ')def(c()):返回r ' '(?ix) %s(?s*(什么?和|或) s * % s s *)* %(s(),s())打印A:t ',a()打印OP:t ',OP()打印项目:t ',项目()打印item : t ',ITEMS()打印S:t ',s()打印C:t ',c()该代码在我的机器上(Ubuntu 10.04,Python 2.6.5)运行的结果是:复制代码代码如下: A: [w.`] OP:(?[=]{1,2 } |介于|相似|在)项目:(?[ w `] |(?Pquote_a[''])(?\['']|[^''])*?(?P=quote_a)) ITEMS: (s*(什么?[ w `] |(?Pquote_b[''])(?\['']|[^''])*?(?P=quote_b))(?s*?[ w `] |(?Pquote_c[''])(?\['']|[^''])*?(?p=quote _ c)))* s * )s 3360[ w `] s *(什么?[=]{1,2 } |介于|相似|在)s*(之间?w |(?Pquote_d[''])(?\['']|[^''])*?(?P=quote_d) | (s*?[ w `] |(?Pquote_e[''])(?\['']|[^''])*?(?P=quote_e))(?s*?[ w `] |(?Pquote_f[''])(?\['']|[^''])*?(?P=quote_f)))* s* ) ) C:(?IX)[ w `] s *(什么?[=]{1,2 } |介于|相似|在)s*(之间?w |(?Pquote_g[''])(?\['']|[^''])*?(?P=quote_g) | (s*?[ w `] |(?Pquote_h[''])(?\['']|[^''])*?(?P=quote_h))(?s*?[ w `] |(?Pquote_i[''])(?\['']|[^''])*?(?P=quote_i)))* s* ))(?s*(什么?和|或) s *[ w `] s *(什么?[=]{1,2 } |介于|相似|在)s*(之间?w |(?Pquote_j[''])(?\['']|[^''])*?(?P=quote_j) | (s*?[ w `] |(?Pquote_k[''])(?\['']|[^''])*?(?P=quote_k))(?s*?[ w `] |(?Pquote_l[''])(?\['']|[^''])*?(?P=quote_l)))* s* ) ) s* )*请看匹配效果图
算术表达式我记得刚才说“为了简单起见,这里不考虑算术表达式”。但是解析算术表达式是一个非常有趣的话题,任何算法书都会提到(中缀表达式到前缀表达式等等)。当然也可以用正则表达式来描述。主要思想是复制代码如下: expr-expr term | expr-term | term term-term * factor | term/factor | factor-digit |(expr)和代码:复制代码如下: #!/usr/bin/python #-*-coding : utf-8-*-# # author : rex # blog 3360 http://jb51.net # filename math . py # created : 2010-08-07 00:44 integer=r ' d ' factor=r ' % s(?.“%s”)”%(整数,整数)项='%s(? s* [*/] s* %s)* ' %(因子,因子)expr='(?x) %s(?3360 s * [-] s *% s) *'%(术语,术语)打印expr查看其输出和匹配渲染:。
提示:如果不用复杂的正则表达式就能解决问题,那就不要用。如果一定要写复杂的正则表达式,请参考以下原则。从大的方面来看,首先了解待解析文本的整体结构,并将其划分为小部件;我们从细节出发,努力实现每一个小部件,力求让每一个部分都完整牢固,放在大局中也不会冲突。正确组装这些零件。分而治之的好处:当只有一个模块出错,其他部分正确时,可以快速定位错误,消除bug。除非你知道你在做什么,它会有什么副作用,以及是否有可行的解决方案,否则请小心使用捕获括号。对于短正则表达式,多一两个括号是无害的;但是对于复杂的正则表达式,一对额外的括号可能是致命的错误。尝试使用自由空间模式。此时,您可以自由添加注释和空白字符,以提高正则表达式的可读性。