• 使用Python运算一个字符串表达式


    概述:

        如何运行一个表达式,例如:12+23*4/2这个我想大家都很了解。不过,如果这个表达式是一个字符串呢?或是这样来描述,一个表达式被写成了一个字符串,我们又应该如何去运行并求得值呢?你是否会想,如果我们能够拿到12, 23, 4, 2以及中间的运算符,那就是真的太好了。而事实上,我们也正是在朝着这个方向去努力。如果你学过算法或是数据结构,那我想这个小问题便不会阻止你前进了。

    思路分析:

        如概述所说,如果我们能拿到字符串表达式中中各个我们肉眼能够识别的“元素”,就算我们迈过了第一步。什么!才第一步?是的,这才是第一步。那第二步是什么?
        没错,第二步就是运算。运算的过程会有一个难题,这个难题就是操作符的优先级问题,就拿上面的表达式来说,我们需要先进行23*4的运算,而不是12+23的运算。我们要做的就是让计算机按照我们认知中的优先来做运算。比较笨的方法就是依次遍历两遍表达式(事实上在后期的运算中,我们遍历的是一个列表)。第一遍先做乘除、第二遍再做加减。

    元素分离:

        对于这一步操作在Python中进行的确很省事,因为我们可爱的Python可以在列表中存储不同类型的对象。这就有点像C中的结构体和Java中的类。我们首先得到的是一个个的字符,再对这些字符进行遍历和分类(是数字还是操作符)。

    # split expression
    def mixed_operation (exp):
        exp_list = list(exp)
        temp = ''
        behavor_list = []
        i = 0
        length = len(exp_list)
        for item in exp_list:
            if is_operation(item):
                behavor_list.append(int(temp))
                behavor_list.append(item)
                temp = ''
            else:
                temp += item
    
            if i == length - 1:
                behavor_list.append(int(temp))
                break;
    
            i += 1
    
        return behavor_list

    逻辑运算:

        这个函数有一些特别,对于有编程经验的朋友可能已经不陌生。对,就是递归!对于一个coder,递归是必须掌握的,就让我们一起在合适的时候把递归搞起吧。这里写递归的原因就是我们的表达式中每一种运算符不可能只有一种。我们要一直这样遍历下去。这时可能你已经感觉到了,遍历的话,为什么不用for?是的,在我的代码里也有for的循环代码,不过这里的for可没有想像中那么好用,不信你可以试试看。

    # Calculation op1 and op2('*' and '/' or '+' and '-')
    def cal_op1_op2(exp_list, op1, op2):
        if len(exp_list) == 1:
            return exp_list
            
        i = 0
        has_op = False
        for i in range(2, len(exp_list), 2):
            a = exp_list[i - 2]
            o = exp_list[i - 1]
            b = exp_list[i]
            if o == op1 or o == op2:
                has_op = True
                exp_list[i - 2] = get_aob(a, o, b)
                del exp_list[i]
                del exp_list[i - 1]
                break
    
        if has_op == False:
            return exp_list
    
        return cal_op1_op2(exp_list, op1, op2)

    特别说明:

        当然对于这个程序来说,并不是那么健壮。因为我们这些逻辑的前提是我们得到了一个正常的表达式,且不包含括号。所谓正常表达式,就是不会出现少数字或是少操作符或是输入了非'+'、'-'、'*'、'/'、[0-9]的字符或是字符集。我们的程序默认了一个理想的运行环境,因为只是说明代码的思路。

    附完整代码:

    #!/usr/bin/env python
    
    'expression_cal.py -- cal the expression that you give to me'
    
    # judgment a char is a operation or not
    def is_operation(oper):
        if oper == '+' or oper == '-' or oper == '*' or oper == '/':
            return True
        else:
            return False
    
    # split expression
    def mixed_operation (exp):
        exp_list = list(exp)
        temp = ''
        behavor_list = []
        i = 0
        length = len(exp_list)
        for item in exp_list:
            if is_operation(item):
                behavor_list.append(int(temp))
                behavor_list.append(item)
                temp = ''
            else:
                temp += item
    
            if i == length - 1:
                behavor_list.append(int(temp))
                break;
    
            i += 1
    
        return behavor_list
    
    # cal a o b
    def get_aob(a, o, b):
        if o == '+':
            return a + b
        elif o == '-':
            return a - b
        elif o == '*':
            return a * b
        elif o == '/':
            return a / b
    
    # Calculation op1 and op2('*' and '/' or '+' and '-')
    def cal_op1_op2(exp_list, op1, op2):
        if len(exp_list) == 1:
            return exp_list
            
        i = 0
        has_op = False
        for i in range(2, len(exp_list), 2):
            a = exp_list[i - 2]
            o = exp_list[i - 1]
            b = exp_list[i]
            if o == op1 or o == op2:
                has_op = True
                exp_list[i - 2] = get_aob(a, o, b)
                del exp_list[i]
                del exp_list[i - 1]
                break
    
        if has_op == False:
            return exp_list
    
        return cal_op1_op2(exp_list, op1, op2)
    
    # cal exp
    def cal_exp(exp_list):
        exp_list = cal_op1_op2(exp_list, '*', '/')
        exp_list = cal_op1_op2(exp_list, '+', '-')
        
        return exp_list[0]
    
    while True:
        expre = raw_input('Enter your expression(0 to end):
    ')
        if expre == '0':
            break
    
        result = mixed_operation(expre)
        print 'list result = ',
        print result
        print cal_exp(result)
    
    print 'END'

    这里符一段《Python核心编程》中第11章中一个示例:算术游戏(easyMath.py)

    #!/usr/bin/env python
    
    from operator import add, sub
    from random import randint, choice
    
    ops = {'+': add, '-': sub}
    
    MAXTRIES = 2
    
    def doprob():
        op = choice('+-')
        nums = [randint(1, 10) for i in range(2)]
        nums.sort(reverse = True) # reverse nums by sorted
        ans = ops[op](*nums) # calculate the right result
        
        pr = '%d %s %d = ' % (nums[0], op, nums[1])
        oops = 0 # record calculate times
        while True:
            try:
                if int(raw_input(pr)) == ans:
                    print 'Correct!'
                    break
                if oops == MAXTRIES:
                    print 'answer
    %s%d' % (pr, ans)
                else:
                    print 'incorrect... try again'
                    oops += 1
            except (KeyboardInterrupt, EOFError, ValueError):
                print 'invalid input... try again'
                    
    def main():
        while True:
            doprob()
            try:
                opt = raw_input('Again? [y]').lower()
                if opt and opt[0] == 'n':
                    break
            except (KeyboardInterrupt, EOFError):
                break
                
    if __name__ == '__main__':
        main()


    注:在原有程序的基础上,我添加了两行注释。的确是感觉这个小程序非常的好,所以在我看到第11章的时候,就忍不住要把这个小程序放到我的博客中来。整个代码的风格也是很值得学习和借鉴的。

  • 相关阅读:
    #Laravel 笔记# 多语言化 App::setLocale() 持久化。
    thinkphp 3.2 发送邮件(Phpmailer)
    深度学习的注意力机制
    图像检索引擎vearch安装与测试使用
    word2vector
    GPU环境搭建
    ImportError: libSM.so.6: cannot open shared object file: No such file or dir
    shell中&&和||的用法
    Linux 远程连接sftp与ftp
    mysql-connector-java各版本及与mysql、JDK版本的对应
  • 原文地址:https://www.cnblogs.com/fengju/p/6336097.html
Copyright © 2020-2023  润新知