Python正则匹配CREATE TABLE类SQL返回None的原因及解决方法
问题原因
- 你的怀疑是对的,匹配失败确实和开头的换行符有关,核心是两点:
- Python的
re.match()方法强制从字符串的第一个字符开始匹配,只要起始位置不符合正则规则,直接返回None,不会自动跳过开头的无关字符往后找 - 你传入的SQL字符串第一个字符是换行符
\n,但正则写的是从create关键字开始匹配,开头的换行不在匹配范围内,自然拿不到结果 - 你在regex101能匹配成功,是因为平台默认是扫描整个字符串找匹配项的模式(对应Python里的
re.search()),不是强制锚定字符串起始位置的match模式,所以结果有差异
- Python的
- 顺便提一句你当前正则的遗漏点:没有覆盖
CREATE TEMPORARY TABLE、CREATE GLOBAL TEMP TABLE这类常见临时表语法,也没处理CREATE OR REPLACE TEMP TABLE这种OR REPLACE和临时表关键字组合的写法,实际用的时候容易漏判。
修复方法
选任意一种都能解决问题:
方案1:最小改动,换用re.search()
re.search()会扫描整个字符串,找到第一个符合规则的位置就返回结果,自动跳过开头的换行、空格、制表符等无关字符,不用改正则逻辑就能跑通:
import re sql = '\nCREATE TABLE tabename \nAS\nSELECT 1' # 优化了正则覆盖更多建表场景,不需要的话可以换回你原来的正则写法 rgxddl = re.compile( r"create\s+(?:(?:or\s+replace\s+)?(?:global\s+)?(?:temp|temporary)\s+table|or\s+replace\s+table|table)\s+[\s\S]*", re.IGNORECASE ) m = rgxddl.search(sql) # 把原来的match替换成search即可
注:你原来加的re.MULTILINE标志对当前正则没用,这个标志只影响^和$的锚定逻辑,你正则里没用到这两个符号,可以删掉。
方案2:保留re.match()的话,在正则开头补空白匹配
如果业务逻辑要求必须从字符串起始位置做匹配,就在正则最前面加\s*,允许开头出现0到多个任意空白字符(包含换行、空格、缩进),再匹配create关键字:
import re sql = '\nCREATE TABLE tabename \nAS\nSELECT 1' rgxddl = re.compile( # 开头加\s*匹配前置空白 r"\s*create\s+(?:(?:or\s+replace\s+)?(?:global\s+)?(?:temp|temporary)\s+table|or\s+replace\s+table|table)\s+[\s\S]*", re.IGNORECASE ) m = rgxddl.match(sql)
方案3:预处理SQL字符串
匹配前先把SQL首尾的空白字符全部去掉,从根源上避免前置换行、空格的干扰,逻辑更直观:
sql = sql.strip() # 去掉首尾所有空白(换行、空格、制表符) # 后续再用原来的rgxddl.match(sql)就能正常匹配
额外提醒
你现在正则末尾用的[\s\S]*会匹配到字符串结束,如果待检测的SQL是多语句用分号拼接的,会把CREATE TABLE后面的所有其他SQL语句都算到建表语句里,实际业务用的话建议按需调整匹配终止边界。
内容的提问来源于stack exchange,提问作者Leo
相关产品推荐
相关产品推荐

