在Python中动态替换字符串
我有一些用字符串表示的多变量数学函数,这些函数在独立变量的表示上有一些特定的约定。
举个例子:
f_sym_st="(sin(x0))**2+exp(x1)*cos(x2)"
我在不同的计算中使用这些函数。为了使用scipy的最小化功能,需要遵循以下关于x的约定。
f_opt_st="(sin(x[0]))**2+exp(x[1])*cos(x[2])"
我使用
f_opt_st=f_sym_st.replace("x0","x[0]").replace("x1","x[1]").replace("x2","x[2]")
这个方法可以工作,但我想找一个更灵活的方式。如果f_sym是来自另一个脚本,并且有,比如说,21个独立变量呢?
“想法”:
for i in range(0,21,1):#end of loop should also be variable
f_sym_st=f_sym_st.replace("xi","x[i]")# obviously iteration does not work in strings
f_opt_st=f_sym_st
这是一个例子 - 基本上我想知道有没有办法动态地替换字符串?
2 个回答
1
使用格式化功能:
for i in range(0,21,1):
f_sym_st=f_sym_st.replace("x{0}".format(i),"x[{0}]".format(i))
2
In [10]: import re
In [11]: f_sym_st = "(sin(x0))**2+exp(x1)*cos(x2)"
In [12]: f_opt_st = re.sub(r"\bx(\d+)", r"x[\1]", f_sym_st)
In [13]: f_opt_st
Out[13]: '(sin(x[0]))**2+exp(x[1])*cos(x[2])'
这里的模式r"\bx(\d+)"
是用来匹配一个单词边界,后面跟着字母x
,然后是一串数字。括号把\d+
包起来,这样数字就会被当作一个组保存。这个组在替换字符串中用\1
来引用。
如果你想把索引减一,可以把替换字符串改成r"x[\1-1]"
。比如:
In [56]: s = "x1*sin(x2) + x10"
In [57]: re.sub(r"\bx(\d+)", r"x[\1-1]", s)
Out[57]: 'x[1-1]*sin(x[2-1]) + x[10-1]'
因为这只是字符串替换,所以它不会把1-1
简化成0
。
如果你不想让里面有那么多-1
,那么你可能就不想用re.sub
。相反,你可以做一些其他的事情,比如下面这样,使用re.findall
来找到表达式中用到的索引:
In [132]: s = "x1*sin(x2) + x10*cos(x2)"
In [133]: indices = sorted(set(int(n) for n in re.findall(r'\bx(\d+)', s)), reverse=True)
In [134]: indices
Out[134]: [10, 2, 1]
In [135]: t = s[:] # Make a copy of s.
In [136]: for ind in indices:
.....: t = t.replace('x' + str(ind), 'x[' + str(ind-1) + ']')
.....:
In [137]: t
Out[137]: 'x[0]*sin(x[1]) + x[9]*cos(x[1])'
如果你愿意,for
循环也可以改成使用format
方法:
In [140]: for ind in indices:
.....: t = t.replace("x{0}".format(ind), "x[{0}]".format(ind-1))
.....: