如何替换“ x!”与'math.factorial(x)'智能地

时间:2019-03-09 00:07:30

标签: python python-3.x replace

我目前正在用Python实现图形计算器,您可以键入自然表达式并对其求值。对于大多数函数或运算符而言,这不是问题,但是由于阶乘函数在操作数之后用!表示,因此更加困难。

我所拥有的是一个包含函数的字符串,例如:'(2x + 1)!',需要替换为:'math.factorial((2x + 1))'

但是,字符串还可以包含其他术语,例如:'2*x + (2x + 1)! - math.sin(x)' 并且析因项不一定包含方括号:'2!'

我一直在寻找解决此问题的方法,但是无济于事,我认为string.replace()方法不能直接做到这一点。我追求的目标是否太雄心勃勃,或者有什么方法可以使我达到预期的效果?

2 个答案:

答案 0 :(得分:2)

您的问题有两个答案:(1)解决您当前的问题; (2)解决您的一般问题。

(1)非常简单-用于进行字符串模式匹配和替换的最常见,通用的工具是Regular Expressions(RE)。您只需定义所需的模式,想要的模式,然后将RE引擎传递给您的字符串。 Python具有re内置的RE module。大多数语言都有类似的东西。某些语言(例如Perl)甚至将其作为语言语法的核心部分。

模式是一系列特定字符或非特定(“通配符”)字符。因此,在您的情况下,您希望非特定字符位于特定的“!”之前字符。您似乎建议您的情况中的“在...之前”是指所有非空白字符,或者如果后续字符是')',则表示该字符与后续过程'('之间的所有字符。因此,让我们构建该模式,从不带括号的版本开始:

[\w] - the set of characters which are letters or numbers (we need a set of
       characters that doesn't include whitespace or ')' so I'm taking some
       liberty to keep the example simple - you could always build your own
       more complex set with the '[]' pattern)
+    - at least one of them
!    - the '!' character

然后是带有括号的版本:

\(  - the literal '(' character, as opposed to the special function that ( has
.   - any character
+   - at least one of them
?   - but dont be "greedy", ie. only take the smallest set of characters that
      match the pattern (will work out to be the closest pair of parentheses)
\)  - the closing ')' character
!   - the '!' character

然后我们只需要将它们放在一起。我们使用|来匹配第一个模式或第二个模式。我们使用()来表示我们要“捕获”的模式部分-在“!”之前并在后面要使用的括号内。这样您的模式就会变成:

([\w]+)!|\((.+?)\)!

不用担心,RE表达式总是看起来像是有人在捣碎键盘一样。有一些很棒的工具,例如RegExr,可以帮助分解复杂的RE表达式。

最后,您只需要进行捕获并将其粘贴在“ math.factorial”中即可。 \x表示第x个匹配项。如果第一个模式匹配,\2将为空白,反之亦然,因此我们可以一次使用它们。

math.factorial(\1\2)

就是这样!这里是如何在Python中运行RE的方法(请注意在字符串之前,r会阻止Python尝试将\作为转义序列进行处理)

import re
re.sub(r'([\w]+)!|\((.+?)\)!', r'math.factorial(\1\2)', '2*x + (2x + 1)! - math.sin(x) + 2!')

re.sub具有三个参数(加上一些此处未使用的可选参数):RE模式,替换字符串和输入字符串。这将产生:

'2*x + math.factorial(2x + 1) - math.sin(x) + math.factorial(2)'

我相信你在追求什么。

现在,(2)更难了。如果您的目的确实是要实现一个将字符串作为输入的计算器,那么您很快就会陷入正则表达式中。在输入的内容和Python可以解释的内容之间会有如此多的例外和变化,以至于您最终会得到一些非常脆弱的东西,这将在它第一次与用户联系时失败。如果您不打算吸引用户,那么您会很安全-您可以坚持使用有效的模式。如果没有,那么您会发现模式匹配方法有些局限。

通常,您要解决的问题称为词法分析(或更全面地说,是词法分析句法分析的三步过程语义分析)。解决此问题的标准方法是使用称为递归下降解析的技术。

有趣的是,Python解释器在解释上面的re语句时完全执行了此过程-编译器和解释器都承担相同的过程,将字符串转换为可以由计算机处理的令牌。

您会在网上找到很多教程。它比使用RE复杂一些,但可以使通用性大大提高。您可能要从非常简短的介绍here开始。

答案 1 :(得分:1)

  1. 您可以删除括号并以线性形式计算所有内容,以便在解析括号时将评估操作数,然后按书面顺序应用阶乘函数。
  2. 或者,您可以获取字符串中阶乘!的索引,然后,如果之前索引处的字符是右括号),则您知道有一个带括号的操作数需要在应用math.factorial()之前进行了计算。