在Python中动态替换字符串

1 投票
2 回答
1574 浏览
提问于 2025-04-18 08:44

我有一些用字符串表示的多变量数学函数,这些函数在独立变量的表示上有一些特定的约定。

举个例子:

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

你可以使用来自re库的sub函数:

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))
   .....:     

撰写回答