我目前正在用Python实现图形计算器,您可以键入自然表达式并对其求值。对于大多数函数或运算符而言,这不是问题,但是由于阶乘函数在操作数之后用!
表示,因此更加困难。
我所拥有的是一个包含函数的字符串,例如:'(2x + 1)!'
,需要替换为:'math.factorial((2x + 1))'
但是,字符串还可以包含其他术语,例如:'2*x + (2x + 1)! - math.sin(x)'
并且析因项不一定包含方括号:'2!'
我一直在寻找解决此问题的方法,但是无济于事,我认为string.replace()
方法不能直接做到这一点。我追求的目标是否太雄心勃勃,或者有什么方法可以使我达到预期的效果?
答案 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)
!
的索引,然后,如果之前索引处的字符是右括号)
,则您知道有一个带括号的操作数需要在应用math.factorial()之前进行了计算。