如何用Python正则表达式提取文本中所有多行SQL SELECT语句块?
解决SQL SELECT语句块提取的正则问题
首先,你的问题核心卡在两个点上:正则默认不支持跨行匹配,加上贪婪匹配的逻辑错误,导致要么只能抓固定行数,要么直接匹配不到结果。咱们一步步来搞定它:
问题根源拆解
你之前用的\(?select.*(\n.*)*[;\)]没结果,主要原因是:
- 正则里的
.默认不匹配换行符,所以.*只能扫单行内容,跨行的语句直接被忽略; - 就算加了
(\n.*)*,没启用跨行匹配标志的话,还是没法识别换行后的内容; - 贪婪模式的
.*会尽可能匹配最长内容,很容易把多个SELECT语句合并成一个结果,反而漏掉目标块。
修正后的正则方案
试试这个配合跨行标志的非贪婪正则,能适配任意行数的SELECT语句,包括带括号的子查询:
import re sql_que = """ select p.value_n, p.enabled from proper p; select p.value_n, p.enabled from proper p where p.property_name = 'PROP1'; (select p.value_n, p.enabled from proper p where p.property_name = 'PROP1' union all select p.value_n, p.enabled from proper p where p.property_name = 'PROP2' )""" # 适配任意行数的SELECT匹配正则 pattern = r'\(?select.*?[;\)]' # 启用DOTALL让.匹配换行,IGNORECASE兼容大小写的SELECT matches = re.findall(pattern, sql_que, re.DOTALL | re.IGNORECASE) # 输出匹配结果 for idx, match in enumerate(matches, 1): print(f"匹配到的SELECT语句块 {idx}:\n{match.strip()}\n")
正则各部分说明
\(?:匹配可选的开头括号,兼容子查询场景;select:匹配SELECT关键字(加IGNORECASE可以处理大小写混合的情况);.*?:非贪婪匹配任意字符(包括换行,因为有DOTALL),直到遇到最近的结束符;[;\)]:匹配语句结束标记,分号或者闭合括号。
运行这段代码后,你会得到三个正确的SELECT块:
select p.value_n, p.enabled from proper p;select p.value_n, p.enabled from proper p where p.property_name = 'PROP1';(select p.value_n, p.enabled from proper p where p.property_name = 'PROP1' union all select p.value_n, p.enabled from proper p where p.property_name = 'PROP2' )
复杂场景的更优方案:用SQL解析库
如果你的SQL涉及多层嵌套括号、注释、复杂语法,正则很容易失效。这时候推荐用专门的SQL解析库sqlparse,能更可靠地处理各种SQL结构:
首先安装库:
pip install sqlparse
然后用代码提取SELECT语句:
import sqlparse sql_que = """ select p.value_n, p.enabled from proper p; select p.value_n, p.enabled from proper p where p.property_name = 'PROP1'; (select p.value_n, p.enabled from proper p where p.property_name = 'PROP1' union all select p.value_n, p.enabled from proper p where p.property_name = 'PROP2' )""" # 解析SQL内容 parsed = sqlparse.parse(sql_que) # 筛选所有SELECT语句 select_statements = [] for stmt in parsed: if stmt.get_type() == 'SELECT': # 格式化语句,让输出更整洁 select_statements.append(sqlparse.format(stmt.to_unicode(), reindent=True)) # 输出结果 for idx, stmt in enumerate(select_statements, 1): print(f"提取到的SELECT语句 {idx}:\n{stmt}\n")
这个方法能完美处理嵌套子查询、复杂语法,比正则更稳定。
内容的提问来源于stack exchange,提问作者senek




