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

rtr*_*ker 5 python string sympy

我有很多长字符串(每个字符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])'
Run Code Online (Sandbox Code Playgroud)

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

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])
Run Code Online (Sandbox Code Playgroud)

长行代码变得笨拙并且使我的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]))
Run Code Online (Sandbox Code Playgroud)

我想要一些功能或功能,将为我提供换行.我已经尝试过使用该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])
Run Code Online (Sandbox Code Playgroud)

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

  1. 将整个表达式括起来().
  2. 后空白或宽分割在大约70个字符+,-,*,],).

aba*_*ert 8

首先,只是通过break_long_words=False将阻止它label在中间分裂.

但这还不足以解决您的问题.输出有效,但可能超过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])
Run Code Online (Sandbox Code Playgroud)

幸运的是,虽然textwrap不能做世界上的一切,但它也可以提供很好的示例代码.这就是为什么文档直接链接到.

你想要的本质上是break_on_hyphens,但也打破算术运算符.所以,如果你只是改变正则表达式使用(-|\+|\*\*|\*)wordsep_re,这可能是所有需要.或者它可能需要更多的工作,但它应该很容易从那里弄清楚.

这是一个例子:

class AlgebraWrapper(textwrap.TextWrapper):
    wordsep_re = re.compile(r'(\s+|(?:-|\+|\*\*|\*|\)|\]))')
w = AlgebraWrapper(break_long_words=False, break_on_hyphens=True)
print w.fill(a)
Run Code Online (Sandbox Code Playgroud)

这会给你:

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])
Run Code Online (Sandbox Code Playgroud)

但实际上,你很幸运,它不需要在括号或parens上打破,因为就像我写的一样简单,它会在括号之前就像在一个括号之后一样容易打破,这在语法上是有效的,但是十分难看.同样的事情是运营商真实的,但它远不如丑陋之前打破*].所以,我可能只关注实际的运算符,并将其保留在:

wordsep_re = re.compile(r'(\s+|(?:-|\+|\*\*|\*))')
Run Code Online (Sandbox Code Playgroud)

如果这是不可接受的,那么你将不得不想出你真正想要的正则表达式而不是它wordsep_re.


另一种解决方案是装饰 - 包装 - 不合格.例如:

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

当然这并不完美 - 它不会优先考虑现有空间而不是添加空间,并且它将填充少于70列(因为它将计算这些添加的空间朝向极限).但如果你只是寻找快速和肮脏的东西,它可能会起作用,如果不是,它可能至少是你实际需要的起点.


无论哪种方式,将整个事物包含在parens中的最简单方法是预先做到:

if len(a) >= 70:
    a = '({})'.format(a)
Run Code Online (Sandbox Code Playgroud)