提取和替换查询参数的python正则表达式-cx\U oracle要求

提取和替换查询参数的python正则表达式-cx\U oracle要求,python,sql,regex,cx-oracle,Python,Sql,Regex,Cx Oracle,python模块cx_Oracle要求,如果在where语句中传递字符串,则查询必须参数化。我从一个文件中读取查询,这些查询看起来就像是从一个类似IDE的sql开发人员那里执行查询一样 示例查询 select name, count(1) from employees where status = 'Active' and role= 'Manager' group by name order by 1; 我想编写一些函数,将此查询作为输入,然后将参数作为元组输出: query = 'sele

python模块cx_Oracle要求,如果在where语句中传递字符串,则查询必须参数化。我从一个文件中读取查询,这些查询看起来就像是从一个类似IDE的sql开发人员那里执行查询一样

示例查询

select name, count(1) from employees where status = 'Active' and role= 'Manager' group by name order by 1;
我想编写一些函数,将此查询作为输入,然后将参数作为元组输出:

query = 'select name, count(1) from employees where status = :1 and role= :2 group by name order by 1;'
parms = ('Active','Manager')
这样,我就可以在一个简单的函数中传递这两个参数来执行查询:

cursor_object.execute(query,parms)
不幸的是,我在正则表达式方面非常糟糕,我已经尝试了好几个小时,但都没有用。

给你:

import re

sql = """select name, count(1) from employees where status = 'Active' and role= 'Manager' group by name order by 1;"""

rx = re.compile(r"""\w+\s*=\s*'([^']+)'""")
params = rx.findall(sql)
print(params)
# ['Active', 'Manager']
主体是

\w+\s*=\s*'([^']+)'
分解后,这表示:

\w+\s*    # 1+ word characters, 0+ whitespace characters
=\s*      # =, 0+ whitespace characters
'([^']+)' # '(...)' -> group 1
看。
要同时拥有查询和参数,可以编写一个小函数:

import re

sql = """select name, count(1) from employees where status = 'Active' and role= 'Manager' group by name order by 1;"""

rx = re.compile(r"""(\w+\s*=\s*)'([^']+)'""")

def replacer(match):
    replacer.params.append(match.group(2))
    return '{}:{}'.format(match.group(1), len(replacer.params))

replacer.params = list()
query = rx.sub(replacer, sql)
params = replacer.params

print(query)
print(params)
# select name, count(1) from employees where status = :1 and role= :2 group by name order by 1;
# ['Active', 'Manager']
如注释中所述,您需要为每个要分析的查询重置参数列表。

给您:

import re

sql = """select name, count(1) from employees where status = 'Active' and role= 'Manager' group by name order by 1;"""

rx = re.compile(r"""\w+\s*=\s*'([^']+)'""")
params = rx.findall(sql)
print(params)
# ['Active', 'Manager']
主体是

\w+\s*=\s*'([^']+)'
分解后,这表示:

\w+\s*    # 1+ word characters, 0+ whitespace characters
=\s*      # =, 0+ whitespace characters
'([^']+)' # '(...)' -> group 1
看。
要同时拥有查询和参数,可以编写一个小函数:

import re

sql = """select name, count(1) from employees where status = 'Active' and role= 'Manager' group by name order by 1;"""

rx = re.compile(r"""(\w+\s*=\s*)'([^']+)'""")

def replacer(match):
    replacer.params.append(match.group(2))
    return '{}:{}'.format(match.group(1), len(replacer.params))

replacer.params = list()
query = rx.sub(replacer, sql)
params = replacer.params

print(query)
print(params)
# select name, count(1) from employees where status = :1 and role= :2 group by name order by 1;
# ['Active', 'Manager']

如注释中所述,您需要为每个要分析的查询重置参数列表。

一个快速而肮脏的解决方案是编写一个与引用字符串匹配的正则表达式。你可以这样开始:

import re
import textwrap

query = textwrap.dedent("""\
select name, count(1)
from employees
where status = 'Active' and role= 'Manager'
group by name order by 1;""")

sub_var = re.compile(r"'[^']+'").sub

print(sub_var("VAR", query))
# select name, count(1)
# from employees
# where status = VAR and role= VAR
# group by name order by 1;
但是,这里您需要替换为一个值,该值会为每个匹配自身递增

为此,您需要一个函数。请记住,
re.sub
可以将可调用作为替换sting。可调用对象必须将MatchObject作为参数并返回替换项

在这里,我更喜欢使用可调用类:

class CountVar(object):
    def __init__(self):
        self.count = 0

    def __call__(self, mo):
        self.count += 1
        return ":{0}".format(self.count)


print(sub_var(CountVar(), query))
# select name, count(1)
# from employees
# where status = :1 and role= :2
# group by name order by 1;

给你

一个快速而肮脏的解决方案是编写与引用字符串匹配的正则表达式。你可以这样开始:

import re
import textwrap

query = textwrap.dedent("""\
select name, count(1)
from employees
where status = 'Active' and role= 'Manager'
group by name order by 1;""")

sub_var = re.compile(r"'[^']+'").sub

print(sub_var("VAR", query))
# select name, count(1)
# from employees
# where status = VAR and role= VAR
# group by name order by 1;
但是,这里您需要替换为一个值,该值会为每个匹配自身递增

为此,您需要一个函数。请记住,
re.sub
可以将可调用作为替换sting。可调用对象必须将MatchObject作为参数并返回替换项

在这里,我更喜欢使用可调用类:

class CountVar(object):
    def __init__(self):
        self.count = 0

    def __call__(self, mo):
        self.count += 1
        return ":{0}".format(self.count)


print(sub_var(CountVar(), query))
# select name, count(1)
# from employees
# where status = :1 and role= :2
# group by name order by 1;

给你

Jan的答案唯一的问题是它没有生成您想要的带有“:1”、“:2”等的字符串

类似于以下的方法应该可以工作:

import re
i=1
pattern = r"(?<==\s*)'\w+'"
params = []
while True:
    match = re.find( pattern, cmd )
    if match is None: break
    params.append(match.group())
    cmd = re.sub( pattern, ":" + str(i), 1 )
    i += 1
重新导入
i=1

pattern=r“(?Jan的答案的唯一问题是它不会生成您想要的带有“:1”、“:2”等的字符串

类似于以下的方法应该可以工作:

import re
i=1
pattern = r"(?<==\s*)'\w+'"
params = []
while True:
    match = re.find( pattern, cmd )
    if match is None: break
    params.append(match.group())
    cmd = re.sub( pattern, ":" + str(i), 1 )
    i += 1
重新导入
i=1

pattern=r“(?感谢您花额外的时间解释表达式。您的分解和链接演示肯定帮助我理解了表达式是如何构建的。快速跟进问题:“替换者”如何构建函数在完全定义之前引用自身?我听说过自引用函数,但从未见过一个在运行。@sikrut:在
Python
中,函数和其他所有函数一样都是对象,因此您可以添加一个属性,如
params
,它本身可以是字符串、列表甚至是其他函数。@Jan:如果您调用e> replacer
函数多次执行时,累积所有调用的参数。每次调用前需要重置列表:
replacer.params=[]
…@LaurentPorte:这绝对是需要注意的,是的。我已经编辑了答案。感谢你花额外的时间解释这个表达式。你的分解和链接演示肯定帮助我理解了表达式是如何构建的。快速跟进问题:“替换者”如何构建函数在完全定义之前引用自身?我听说过自引用函数,但从未见过一个在运行。@sikrut:在
Python
中,函数和其他所有函数一样都是对象,因此您可以添加一个属性,如
params
,它本身可以是字符串、列表甚至是其他函数。@Jan:如果您调用e> replacer
函数多次执行时,累积所有调用的参数。每次调用前需要重置列表:
replacer.params=[]
…@LaurentPorte:这肯定是需要注意的,是的。我已经编辑了答案。谢谢你提供了这个解决方案。看到多表达式版本很有趣。为什么要使用类而不是函数的函数?我可能是说更根本的原因,因为我实际上只在我的宠物项目中使用函数。自学ut很多经验感谢您提供这个解决方案。看到多表达式版本很有趣。为什么要使用类而不是函数的函数?我的意思可能更根本,因为我实际上只在我的宠物项目中使用过函数。自学而没有太多经验,可以在一个循环中看到这一点,以及一个额外的表达式Session。没有意识到它们是如此灵活,但可能这也是它们有点难以识别的原因。很高兴看到这在循环中完成,以及一个附加表达式。没有意识到它们是如此灵活,但可能这也是它们有点难以识别的原因。