【问题标题】:Python regex to match SQL INSERT statementsPython 正则表达式匹配 SQL INSERT 语句
【发布时间】:2017-10-27 10:41:31
【问题描述】:

我正在开发一个 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 加载到数据库中,running inspectdb on the database to get an initial Django model file,然后使用dumpdata把它变成固定装置有帮助吗?
  • 考虑编写解析器而不是滥用正则表达式捕获组。我在这里回答了一个类似的问题:stackoverflow.com/questions/42435114/…。如果这有帮助,那就太好了。如果没有,请告诉我,我会看看是否可以为您尝试制作的语言编写语法。

标签: python regex django


【解决方案1】:

停止尝试使用正则表达式解析 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 有一些奇怪的空白行为,在您正确删除之前值得了解。

【讨论】:

  • +1 用于推荐 PyParsing(看起来像一个有趣的包)——我将在未来的项目中使用它,但我觉得它对于这个特定问题来说有点过头了。
【解决方案2】:

如果语句的格式是固定的,那么使用正则表达式就没有什么意义了。只需使用简单的字符串解析:

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)'"]

【讨论】:

  • 我喜欢这个答案。这是最简单的方法 - 我不知道为什么我没有想到...
猜你喜欢
  • 1970-01-01
  • 2016-01-16
  • 1970-01-01
  • 1970-01-01
  • 2013-09-13
  • 2020-08-26
  • 1970-01-01
  • 2016-07-01
相关资源
最近更新 更多