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

Python 如何在表示9000+的数学表达式的字符串中放置适当的换行符;角色?,python,string,sympy,Python,String,Sympy,我有许多表示数学表达式的长字符串(每个都有9000多个字符)。我最初使用Symphy生成表达式,Symphy是一个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]

我有许多表示数学表达式的长字符串(每个都有9000多个字符)。我最初使用Symphy生成表达式,Symphy是一个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作为代码(即,在“和”之间复制文本,然后将其粘贴到函数中作为代码):

代码的长行变得笨拙,减慢了我的IDE(Spyder)的速度,所以我想加入一些换行符(代码可以作为一条长行工作)。我已经成功地手动完成了这项工作,方法是将表达式括在括号中,并自己插入换行符(即根据使用隐式换行符):

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

>>> 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])
手动拆分字符串并在将字符串粘贴为代码时仍保留有效表达式的经验法则如下:

  • 将整个表达式括在
    ()
  • 在空格或
    +
    -
    *
    ]
    ]
    )后以大约70个字符的宽度拆分
  • 首先,只是通过将阻止它在中间分裂<代码>标签< /代码>。< /P> 但这还不足以解决你的问题。输出将有效,但可能超过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
    不能做世界上的所有事情,但它还是很好的示例代码。这就是为什么直接链接到

    您需要的基本上是
    在连字符上断开,但也要在算术运算符上断开。因此,如果您只是将regexp更改为在
    wordsep\u re
    中使用
    (-124\+\*\*\*\*\*.\*)
    ,可能就需要这么多了。或者它可能需要更多的工作,但应该很容易从那里弄清楚

    下面是一个例子:

    class AlgebraWrapper(textwrap.TextWrapper):
        wordsep_re = re.compile(r'(\s+|(?:-|\+|\*\*|\*|\)|\]))')
    w = AlgebraWrapper(break_long_words=False, break_on_hyphens=True)
    print w.fill(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])
    
    但实际上,你很幸运,它不需要在括号或括号上断开,因为正如我写的那样简单,它在括号前断开和在括号后断开一样容易,这在语法上是有效的,但非常难看。同样的道理也适用于操作符,但是在
    *
    之前中断比在
    ]
    之前中断要简单得多。因此,我可能只讨论实际的操作员,并将其保留在以下位置:

    wordsep_re = re.compile(r'(\s+|(?:-|\+|\*\*|\*))')
    
    如果这是不可接受的,那么您必须拿出实际需要的regexp,并将其放在
    wordsep\u re
    的位置


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

    b = re.sub(r'(-|\+|\*\*|\*', r'\1 ', a)
    c = textwrap.fill(b)
    d = re.sub(r'(-|\+|\*\*|\*) ', r'\1', c)
    
    当然,这并不完美,它不喜欢现有的空格而不是添加的空格,而且它会填充到少于70列(因为它会将这些添加的空格计算到极限)。但是,如果你只是在寻找一些快速而肮脏的东西,它可能有用,如果没有,它至少可能是你真正需要的一个起点


    无论采用哪种方式,将整个内容包含在parens中的最简单方法是提前完成:

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

    谢谢@abarnert。用
    break\u long\u words=False快速而肮脏的方法暂时就足够了。大约70个字符的
    行长度比9000个字符好得多。我最长的
    word
    是~100个字符,所以这对于行长度来说是很好的。很好的解决方案。我个人只喜欢打断
    +
    -
    ,因为在SymPy表示法中,它们的周围已经有了空格(这很好地证明了emacs的自动填充方式可以自动完成工作)。但即便如此,这种方法还是更好,因为它将运算符保留在行的末尾而不是开头。因此,我实际上只需要将您的代码环绕
    \s+.
    。无论哪种方式,这在Symphy本身中都可能很有用,因此可以随意提交一个pull请求,将其添加为
    sstr
    @asmurer的一个选项:因为
    +
    -
    已经有空格了,所以
    textwrap
    已经可以很好地处理它们了。唯一的问题是当你有一个66个字符长,没有空格的术语。请参见OP示例中的最后一行。要处理这个问题,您必须同时中断
    *
    /
    。理想情况下,您可能不想在
    **
    上中断,而是想在
    *
    上中断,但这是一个更复杂的regexp,没有人要求它,而且我很懒。:)但是问题是将
    +
    -
    保留在行的末尾,而不是开头。
    b = re.sub(r'(-|\+|\*\*|\*', r'\1 ', a)
    c = textwrap.fill(b)
    d = re.sub(r'(-|\+|\*\*|\*) ', r'\1', c)
    
    if len(a) >= 70:
        a = '({})'.format(a)