如何解析和简化像'3cm /μs²+ 4e-4 sqmiles/km/h**2'的字符串正确处理物理单位?

Tob*_*ler 9 python parsing sympy

我想把一个字符串3cm/µs² + 4e-4 sqmiles/km/h**2分成它的SI单位(在这种情况下m/s**2)和它的大小(以该单位的倍数).

由于sympy提供了解析模块许多物理单元和SI前缀,我想使用sympy将是一个好主意.但实现这一目标的好方法是什么?我会写一个类似下面的算法,但我想避免重新发明方形轮:

  • 将数字和字母(除了4e-4类似的语法)和空格(除非它在显式运算符旁边)之间的转换视为乘法,然后标记化
  • 用SI表示替换每个非数字标记(也检查SI前缀)
  • 将新表达式简化为Magnitude * some SI units(在不一致的单元上给出有意义的错误消息,例如Cannot add m**2 to s)

这可以通过现有手段轻松实现吗?或者如何最好地实施?

Kra*_*nov 4

单位

一种解决方案是从 SymPyunits模块收集所有单位,并使用它们来替换由sympify

>>> import sympy.physics.units as u 
... subs = {} 
... for k, v in u.__dict__.items(): 
...     if isinstance(v, Expr) and v.has(u.Unit): 
...         subs[Symbol(k)] = v # Map the `Symbol` for a unit to the unit

>>> # sympify returns `Symbol`s, `subs` maps them to `Unit`s
>>> print sympify('yard*millimeter/ly').subs(subs)
127*m/1313990343414000000000
Run Code Online (Sandbox Code Playgroud)

如果该符号不在其中,units它将被打印为未知符号(例如barn

>>> print sympify('barn/meter**2').subs(subs)
barn/m**2 
Run Code Online (Sandbox Code Playgroud)

但您随时可以向词典中添加内容subs

>>> subs[Symbol('almost_meter')] = 0.9*u.meter
... sympify('almost_meter').subs(subs)
0.9*m
Run Code Online (Sandbox Code Playgroud)

SI 前缀并不完全按照您想要的方式工作。您将需要添加一个乘号(或者希望它是一个像km显式实现的通用单位)。此外,由于它们不是Unit实例而是Integer实例,因此您必须将它们添加到subs

>>> import sympy.physics.units as u
... subs = {} 
... for k, v in u.__dict__.items(): 
...     if (isinstance(v, Expr) and v.has(u.Unit)) or isinstance(v, Integer): 
...         subs[Symbol(k)] = v 

>>> print sympify('mega*m').subs(subs)
1000000*m 
Run Code Online (Sandbox Code Playgroud)

对于 unicode,您可能需要一些预处理。我认为 SymPy 没有对 unicode 支持做出任何承诺。

如果您实现了 new Units,请考虑在 github 上向它们发出拉取请求。要编辑的文件应该是sympy/physics/units.py.

空格和隐式乘法

在 SymPy 的开发版本中,您可以找到用于假设隐式乘法的代码,其中写入了适当的空格:

>>> from sympy.parsing.sympy_parser import (parse_expr,
... standard_transformations, implicit_multiplication_application)

>>> parse_expr("10sin**2 x**2 + 3xyz + tan theta",
...            transformations=(standard_transformations + 
...                             (implicit_multiplication_application,)))
3*x*y*z + 10*sin(x**2)**2 + tan(theta) 
Run Code Online (Sandbox Code Playgroud)

安全

sympifyeval如果您打算将其用于面向网络的应用程序,则可以利用它!