如何在表示9000多个字符的数学表达式的字符串中放置适当的换行符?

2024-09-24 00:33:59 发布

您现在位置:Python中文网/ 问答频道 /正文

我有许多表示数学表达式的长字符串(每个字符9000多个)。我最初使用sympy生成表达式,这是一个python符号代数包。一个截短的例子是:

a = 'm[i]**2*(zb[layer]*m[i]**4 - 2*zb[layer]*m[j]**2*m[i]**2 + zb[layer]*m[j]**4 - zt[layer]*m[i]**4 + 2*zt[layer]*m[j]**2*m[i]**2 - zt[layer]*m[j]**4)**(-1)*ab[layer]*sin(m[i]*zb[layer])*sin(m[j]*zb[layer])'

最后,我复制了字符串中的文本,然后使用is作为代码(即,复制'and'之间的文本,然后将其作为代码粘贴到函数中):

^{pr2}$

冗长的代码行变得笨拙,减慢了我的IDE(Spyder)的速度,所以我想加入一些换行符(代码可以像一行一样工作)。我通过将表达式括在方括号中并自己加上换行符(即按照PEP8使用隐式行转换),成功地手动完成了这项工作:

def foo(args):
    return (m[i]**2*(zb[layer]*m[i]**4 - 2*zb[layer]*m[j]**2*m[i]**2 + 
        zb[layer]*m[j]**4 - zt[layer]*m[i]**4 + 2*zt[layer]*m[j]**2*m[i]**2 - 
        zt[layer]*m[j]**4)**(-1)*ab[layer]*sin(m[i]*zb[layer])*sin(m[j]*zb[layer]))

我想要一些函数或功能,将放在换行符。我尝试过使用textwrap模块,但这会将行分割成不适当的位置。例如,在下面的代码中,“layer”中间的最后一行拆分使我的数学表达式无效:

>>> import textwrap
>>> a = 'm[i]**2*(zb[layer]*m[i]**4 - 2*zb[layer]*m[j]**2*m[i]**2 + zb[layer]*m[j]**4 - zt[layer]*m[i]**4 + 2*zt[layer]*m[j]**2*m[i]**2 - zt[layer]*m[j]**4)**(-1)*ab[layer]*sin(m[i]*zb[layer])*sin(m[j]*zb[layer])'
>>> print(textwrap.fill(a,width=70))
m[i]**2*(zb[layer]*m[i]**4 - 2*zb[layer]*m[j]**2*m[i]**2 +
zb[layer]*m[j]**4 - zt[layer]*m[i]**4 + 2*zt[layer]*m[j]**2*m[i]**2 - 
zt[layer]*m[j]**4)**(-1)*ab[layer]*sin(m[i]*zb[layer])*sin(m[j]*zb[lay
er])

手动拆分字符串并在将字符串粘贴为代码时仍具有有效表达式的经验法则是:

  1. 将整个表达式括在()中。在
  2. 在空格或+-*])之后,拆分大约70个字符。在

Tags: 函数字符串代码文本layerab表达式粘贴
1条回答
网友
1楼 · 发布于 2024-09-24 00:33:59

首先,仅通过^{}将阻止它在中间分裂^ {< CD2>}。在

但这不足以解决你的问题。输出将有效,但可能超过70列。在您的示例中,它将:

m[i]**2*(zb[layer]*m[i]**4 - 2*zb[layer]*m[j]**2*m[i]**2 +
zb[layer]*m[j]**4 - zt[layer]*m[i]**4 + 2*zt[layer]*m[j]**2*m[i]**2 -
zt[layer]*m[j]**4)**(-1)*ab[layer]*sin(m[i]*zb[layer])*sin(m[j]*zb[layer])

幸运的是,虽然textwrap不能做任何事情,但它也可以生成很好的示例代码。这就是the docs直接链接到the source的原因。在

你想要的基本上是break_on_hyphens,但也要打破算术运算符。因此,如果您只需将regexp更改为在wordsep_re中使用(-|\+|\*\*|\*),那么这可能就是所需的全部内容。或者它可能需要更多的工作,但应该很容易从那里找到答案。在

下面是一个例子:

^{pr2}$

这将为您提供:

m[i]**2*(zb[layer]*m[i]**4 - 2*zb[layer]*m[j]**2*m[i]**2 + zb[layer]*
m[j]**4 - zt[layer]*m[i]**4 + 2*zt[layer]*m[j]**2*m[i]**2 - zt[layer]*
m[j]**4)**(-1)*ab[layer]*sin(m[i]*zb[layer])*sin(m[j]*zb[layer])

但实际上,你很幸运,它不需要在括号或括号上断开,因为就像我写的那样简单,它在括号前和括号后一样容易断开,这在语法上是有效的,但是非常难看。同样的情况也适用于运算符,但是在*之前中断要比在]之前中断要少得多。所以,我可能只考虑实际的操作员,然后就这样:

wordsep_re = re.compile(r'(\s+|(?:-|\+|\*\*|\*))')

如果这是不可接受的,那么您就必须拿出您真正想要的regexp,并将其放在wordsep_re的位置。在


另一个解决方案是装饰包装不装饰。例如:

b = re.sub(r'(-|\+|\*\*|\*', r'\1 ', a)
c = textwrap.fill(b)
d = re.sub(r'(-|\+|\*\*|\*) ', r'\1', c)

当然这并不是完美的,它不喜欢现有的空间而不是增加的空间,它将填充少于70列(因为它将把那些添加的空间计算到极限)。但如果你只是想找些又快又脏的东西,它可能会有用,如果不是的话,它至少可以作为你真正需要的东西的起点。在


不管怎样,最简单的方法是把整件事放在帕伦斯的前面:

if len(a) >= 70:
    a = '({})'.format(a)

相关问题 更多 >