首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将英语翻译为数学并执行运算

将英语翻译为数学并执行运算
EN

Code Review用户
提问于 2017-12-11 20:42:13
回答 1查看 429关注 0票数 4

这样做的目的是接受一个英文的数学运算串,并从左到右对它进行计算。

关于操作顺序:当大声说出操作时,通常用隐含的括号表示从左到右的链。

例如:

4加3乘2平方=== ((4+ 3)乘以2)

人们所说的节奏决定了在乘积之前是否要将2相乘,但在这种情况下,目标是严格地从左向右。

我在这里回顾的起点是我对StackOverflow问题的回答,它是直接的,正确的,但在设计和风格上不令人满意。

代码语言:javascript
复制
import math
import re
import operator

# try "3 add 4 times 5"
inputs = input(">").lower()

# Using RE to find all numbers in string.
numInString = [int(d) for d in re.findall(r'-?\d+', inputs)]
inputs = inputs.split()

print('Numbers found: ', numInString)
print('Inputs found: ', inputs)

# Define all of the operators
def multiplication():
    multAns = operator.mul(numInString.pop(0) , numInString.pop(0))
    numInString.insert(0, multAns)
    print(multAns)

def division():
    divAns = operator.truediv(numInString.pop(0) , numInString.pop(0))
    numInString.insert(0, divAns)
    print(divAns)

def addition():
    addAns = operator.add(numInString.pop(0) , numInString.pop(0))
    numInString.insert(0, addAns)
    print(addAns)

def subtraction():
    subAns = operator.sub(numInString.pop(0) , numInString.pop(0))
    numInString.insert(0, subAns)
    print(subAns)

def squareRoot():
    SqrtAns = math.sqrt(numInString.pop(0))
    numInString.insert(0, SqrtAns)
    print(SqrtAns)

def squared():
    SquareAns = math.pow(numInString.pop(0), 2)
    numInString.insert(0, SquareAns)
    print(SquareAns)

def cubed():
    CubedAns = math.pow(numInString.pop(0), 3)
    numInString.insert(0, CubedAns)
    print(CubedAns)

def power():
    PowerAns = math.pow(numInString.pop(0), numInString[1])
    numInString.insert(0, PowerAns)
    print(PowerAns)

# Dictionary mapping search words to operator function
Operation = {
    'multiply': multiplication,
    'times' : multiplication,
    'multiplied': multiplication,
    'divide': division,
    'divided': division,
    'into': division,
    'add': addition,
    'sum': addition,
    'added': addition,
    'subtract': subtraction,
    'minus': subtraction,
    'take': subtraction,
    'subtracted': subtraction,
    }

for words in inputs:
    if words in Operation:
        print(Operation[words]())
  1. 我应该如何命名变量?OperationnumInString是好名字吗?
  2. 我应该打印函数操作符的结果吗?
  3. 我是否应该将数字存储在全局列表(例如numInString)中,而不是将它们传递给运算符函数?
  4. 我应该打印像这样的错误吗?:打印(“没有给定的操作”)
  5. 假设所有的数字都是int类型可以吗?
  6. 我是否应该保留未加保护的脚本代码(如input('>') )?
EN

回答 1

Code Review用户

回答已采纳

发布于 2017-12-11 20:42:13

  1. 我应该如何命名变量?操作和numInString的好名字?

很好的问题是,Python有一个广泛而又平易近人的风格指南,叫做PEP8。具体来说,局部变量应该是lowercase,全局常量应该是UPPERCASE,并且应该避免全局变量。

  1. 我应该打印函数操作符的结果吗?

为了以后使用它,您应该返回值:

而不是:print(multAns) do return multAns

  1. 我是否应该将数字存储在全局列表numInString中,而不是将它们传递给运算符函数?

不,将数字传递给运算符并保存返回的结果。

代码语言:javascript
复制
result = oper(a=1, b=3)

而不是

代码语言:javascript
复制
a = 1
b = 3
oper()

  1. 我应该像这样print错误吗?:打印(“没有给定的操作”)

不,当你遇到这种情况的时候,就会产生错误。

代码语言:javascript
复制
ValueError("Cannot match an operator to \"{}\"".format(inputstring))

  1. 可以假设所有的数字都是int吗?

处理十进制数的情况会更好,特别是如果您希望能够进行真正的除法(在代码中)。

用大量的评论

我的修订版,包括我上面的建议

代码语言:javascript
复制
import re
from decimal import Decimal

字典映射搜索词到操作符函数

代码语言:javascript
复制
operations = {
    '<a> (times|multiplied by) <b>':
        lambda a, b: a * b,
    '<a> divided by <b>':
        lambda a, b: a / b,
    '(add|sum)? <a> (and|plus) <b>':
        lambda a, b: a + b,
    'subtract <a> and <b>':
        lambda a, b: a - b,
    '<a> (minus|take) <b>':
        lambda a, b: a - b,
    '<a> squared':
        lambda a: a**2,
    '<a> cubed':
        lambda a: a**3,
    '<a> raised to the power <b>':
        lambda a, b: a**b,
    }

把lambda想成"make_function“

代码语言:javascript
复制
def plus(a, b):
    return a + b

is the same as

plus = lambda a, b: a + b

此外,您还可以使用实际的操作员:例如。*代替operator.mul +而不是add

与任何数字相匹配。8,8.8,-3.14 https://stackoverflow.com/questions/15814592/how-do-i-include-negative-decimal-numbers-in-this-regular-expression这被定义为全局常量

代码语言:javascript
复制
NUM_RE = "-?\d+(\.\d+)?"

匹配这个数字,并给它一个可以稍后通过m.groupdict()访问的名称

代码语言:javascript
复制
def named_number_regex(name):
    return "(?P<{name}>{num})".format(name=name, num=NUM_RE)

variable_names = ['a', 'b']
for name in variable_names:
    # replace all of the name placeholders with
    # the actual regex for matching a named number
    #     eg. "<a>" ---> "(?P<a>-?\d+(\.\d+)?)"
    # placeholder were used just to make the above patterns easier to read
    old = '<{}>'.format(name)
    new = named_number_regex(name)
    operations = {k.replace(old, new): v for k, v in operations.items()}

# allow for varying amount of whitespace
operations = {'\s*' + k.replace(' ', '\s*'): v for k, v in operations.items()}

现在的模式如下:

代码语言:javascript
复制
#
# \s*(?P<a>-?\d+(\.\d+)?)\s*squared
#
# let's break it down:
#
# \s*                                 ignore leading whitespace
#    (?P<a>-?\d+(\.\d+)?)             match any number, name it 'a'
#                        \s*          ignore other whitespace
#                           squared   only match if you find " squared"

函数来获取字符串,并递归地将其简化,直到得到一个数字或遇到错误为止。

代码语言:javascript
复制
def simplify(inputstring):
    print(inputstring) # see what is going on internally

    # if you get down to a single number return its value
    if re.fullmatch(NUM_RE, inputstring) is not None:
        return Decimal(inputstring)

    for matcher, oper in operations.items():
        # iterate over all key: value pairs in the dict "operations" eg:
        #    matcher = '(?P<a>\d+) (times|multiplied by) (?P<b>\d+)'
        #    oper = lambda a, b: operator.mul(a, b)
        m = re.match(matcher, inputstring)
        if m is None:
            continue

        # dict of named matches eg {'a': '4', 'b': '8'}
        numbers = m.groupdict()

        # convert text eg. '4' strings into integers eg. 4
        # this is like your [int(d) for d in re.findall(r'-?\d+', inputs)]
        # Decimal handles ints and floats, with floating point rounding errors
        numbers = {k:Decimal(v) for k, v in numbers.items()}

        # now numbers = {'a': 4, 'b': 8}

        # get the result of the matched operation
        # Note: ** means call function with keyword args from a dict
        #     eg. oper(a=4, b=8)
        result = oper(**numbers)

        # substitute the result of oper with the matched string
        # Note we can lose precision here when casting Decimal to str
        simplified = re.sub(matcher, str(result), inputstring)

        # now simplify it further if possible
        # this is call recursion, it will continue to simplify until we get down to just a number
        print('= ', sep='', end='')
        return simplify(simplified)

    raise ValueError("Cannot match an operator to \"{}\"".format(inputstring))

测试用例

代码语言:javascript
复制
def test_a_few_cases():
    print("\nSimple Addition:")
    result = simplify("4 plus 8")

    print("\nDemonstrate the recursion:")
    result = simplify("2 squared squared squared squared")

    print("\nMore elaborate:")
    result2 = simplify("2 plus 1.11 times -7 raised to the power 6")

    print("\nDemonstrate an Error:")
    result = simplify("2 squared squared squared squard")

def main():
    print("\nYour input:")
    yourresult = simplify(input(">").lower())

if __name__ == '__main__':
    test_a_few_cases()
    main()
票数 7
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/182551

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档