Skip to main content
 首页 » 编程设计

用于匹配 SQL INSERT 语句的 Python 正则表达式

2025年02月15日28kuangbin

我在 Django 网站上工作,我正在尝试使用从遗留数据库转储的数据为 Django 创建 YAML 装置。

我正在使用正则表达式编写一个粗略的 SQL 解析器(我知道,我知道......但我找不到任何可以帮助我快速完成此操作的东西,所以我必须“自己动手” - 除非有更好的建议).

“自己动手”解决方案的一部分是解析 SQL 语句 - 这些语句是自动生成的,因此语句的格式不会改变。

这里有两个示例 INSERT 语句:

INSERT INTO ref_geographic_region (continent_id,name) VALUES(8,'Europe (Western)'); 
INSERT INTO ref_currency_group (name) VALUES('Major'); 

我想将 SQL 语句理解为以下模式:

INSERT INTO <table_name> VALUES (one_or_more_alphanums_separated_by_comma); 

然后我需要匹配以下值:

  • 表名
  • one_or_more_alphanums_separated_by_comma

这是我的正则表达式模式。它是匹配的,但分组不是我想要的。

pattern_string = r"INSERT INTO ([a-zA-Z\_]+)\s\(((([a-zA-Z\_]+)(\,)*)+)\)\s+VALUES\(([0-9]*)|([a-zA-Z\(\)']+)(\,)*\;" 

我如何修改(和简化)上面的模式,使其只匹配我感兴趣的标记?

请您参考如下方法:

停止尝试使用正则表达式解析 SQL。这大致与使用正则表达式解析 HTML 一样糟糕,因为 SQL 是一种上下文无关的语言,正则表达式无法处理。使用适当的解析模块(如 PyParsing)可以更轻松地完成此操作

from pyparsing import Regex, QuotedString, delimitedList 
 
# Object names and numbers match these regular expression 
object_name = Regex('[a-zA-Z_]+') 
number = Regex('-?[0-9]+') 
# A string is just something with quotes around it - PyParsing has a built in 
string = QuotedString("'") | QuotedString('"') 
 
# A term is a number or a string 
term = number | string 
 
# The values we want to capture are either delimited lists of expressions we know about... 
column_list = (delimitedList(object_name)).setResultsName('columns') 
term_list = (delimitedList(term)).setResultsName('terms') 
 
# Or just an expression we know about by itself 
table_name = object_name.setResultsName('table') 
 
# And an SQL statement is just all of these pieces joined together with some string between them 
sql_stmt = "INSERT INTO " + table_name + "(" + column_list + ") VALUES(" + term_list + ");" 
 
 
if __name__ == '__main__': 
    res = sql_stmt.parseString("""INSERT INTO ref_geographic_region (continent_id,name) VALUES(8,'Europe (Western)');""") 
    print res.table         # ref_geographic_region 
    print list(res.columns) # ['continent_id', 'name'] 
    print list(res.terms)   # ['8', 'Europe (Western)'] 

这是一个快速的半小时稻草人 - 我建议通读它的 docs并正确理解它是如何工作的。特别是,PyParsing 有一些奇怪的空格行为,在您正确删除之前值得了解。