3

我正在编写一个 python 函数来处理多行 SQL 语句。

例如

multi_stmt = """
-- delete empty responses
DELETE FROM idlongDVR_responses WHERE new_response_code = '';
DELETE FROM idwideDVR_responses WHERE new_response_code = '';

-- create a current responses table for idlongDVR
DROP TABLE IF EXISTS idlongDVR_respCurr;
CREATE  TABLE idlongDVR_respCurr
    SELECT *, MAX(modifiedat) AS latest  FROM idlongDVR_responses
    GROUP BY sitecode, id, dass, tass, field, value, validation_message
    ORDER BY sitecode, id, dass, tass; """

所以我写了一个正则表达式来识别换行符,如果它后面没有双连字符(开始注释),并以分号结尾

sql_line = re.compile(r"""
            \n+         # starting from a new line sequence
            (?!(--|\n)) # if not followed by a comment start "--" or newline 

            (.*?)       # <<<<< WHY ARE THESE CAPTURING BRACKETS NEEDED?

            ;           # ending with a semicolon
                      """, re.DOTALL|re.VERBOSE|re.MULTILINE)

stmts = sql_line.findall(multi_statement)

for stmt in stmts:
    stmt = stmt[1]
    if len(stmt) > 0:
        cursor.execute(stmt)

它可以正常工作,但只有当我将.*?术语括在括号中时它才会变为(.*?). 如果我不这样做,那么我什么都不匹配。

为什么是这样?提前致谢。

4

2 回答 2

2

“需要这些捕获括号”,因为您在负前瞻内使用了捕获括号。

(?!(--|\n))
   ^     ^

由于这永远不应该匹配,因此第一个捕获组在成功匹配中将始终为空。由于某些方法(例如.findall)只会返回捕获组(如果它们存在),因此您只会看到一个空字符串列表。

在此处删除(...)应该使正则表达式的行为符合您的预期。顺便说一句,您可以使用[^;]* 而不是.*?.

sql_line = re.compile(r"\n+(?!--|\n)[^;]*;")
于 2012-08-12T20:27:37.620 回答
0

你在用findall,不是吗? findall很奇怪。如果您在正则表达式中有任何捕获组,它只返回捕获组的内容。正如@KennyTM 指出的那样,您的前瞻中有一个捕获组,并且由于它是一个前瞻,因此只有当该组无法捕获任何内容时,您的整体匹配才会成功。因此,您的空字符串列表。

不要问我为什么当你使用.*?. 通过阅读文档,我希望它返回一个由两组组成的元组列表:一组是空的,一组是您期望的匹配项。但我只得到非空组。这似乎是findall我以前从未遇到过的另一层荒谬。

顺便说一句,你不需要MULTILINE旗帜。所做的只是改变锚点的行为,^并且$允许它们在行边界以及整个字符串的开头和结尾处匹配。也许你已经知道了,但是有一个非常持久的流氓模因漂浮在周围,上面写着“如果它是多行的,你必须使用MULTILINE”,每当我看到它时,我都会尝试在它上面加盖印记。

于 2012-08-12T21:03:00.483 回答