我正在开发一个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);
然后,我需要匹配以下值:
- table_name
- 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)']
这是一个快速的半小时稻草人 - 我建议通读其文档并正确了解其工作原理。特别是,PyParsing在空格方面有一些奇怪的行为,在你正确删除之前值得了解。
如果语句的格式是固定的,那么使用正则表达式就没有什么意义了。只需使用简单的字符串解析:
parts = statement.split(' ', 4)
print(parts[2])
print(parts[3][1:-1].split(','))
print(parts[4][7:-2].split(','))
示例输出:
ref_geographic_region
['continent_id', 'name']
['8', "'Europe (Western)'"]