python中的前缀符号解析

python中的前缀符号解析,python,math,notation,addition,Python,Math,Notation,Addition,马上-不,这不是家庭作业 我想用python编写一个前缀符号解析器(用于当前的求和)。。。比如说 如果给定:+22它将返回:4 想法 prints 4还包括一个乘法运算符,用于显示如何展开它。regex: import re prefix_re = re.compile(r"(+|-|*|/)\s+(\d+)\s+(\d+)") for line in get_lines_to_parse(): match = prefix_re.match(line) if match:

马上-不,这不是家庭作业

我想用python编写一个前缀符号解析器(用于当前的求和)。。。比如说

如果给定:
+22
它将返回:
4

想法

prints 4还包括一个乘法运算符,用于显示如何展开它。

regex:

import re
prefix_re = re.compile(r"(+|-|*|/)\s+(\d+)\s+(\d+)")
for line in get_lines_to_parse():
    match = prefix_re.match(line)
    if match:
        operand = match.group(1)
    if operand == '+':
        return int(match.group(2))+int(match.group(3))
    elif operand == '-':
        return int(match.group(2))-int(match.group(3))
#etc...

前缀表示法可以很容易地递归计算。基本上可以看到第一个标记,如果它是“+”,则计算后面的子表达式以获得要添加的值,然后将它们相加。如果它是一个数字,您只需返回该数字

下面的代码假定输入格式正确,是一个有效的表达式

#! /usr/bin/env python
from collections import deque
def parse(tokens):
    token=tokens.popleft()
    if token=='+':
            return parse(tokens)+parse(tokens)
    elif token=='-':
            return parse(tokens)-parse(tokens)
    elif token=='*':
            return parse(tokens)*parse(tokens)
    elif token=='/':
            return parse(tokens)/parse(tokens)
    else:
            # must be just a number
            return int(token)


if __name__=='__main__':
        expression="+ 2 2"
        print parse(deque(expression.split()))
# Bring in the system module to get command line parameters
import sys

# This function takes in some binary operator, which is just an arbitrary
#  string, and two values.  It looks up the method associated with the
#  operator, passes the two values into that method, and returns the
#  method's result.
def eval_expression(operator, value_one, value_two):
  if operator == "+":
    return value_one + value_two
  elif operator == "-":
    return value_one - value_two
  elif operator == "*":
    return value_one * value_two
  elif operator == "/":
    return value_one / value_two
  # Add new operators here.  For example a modulus operator could be
  #  created as follows:
  #       elif operator == "mod":
  #         return value_one % value_two
  else:
    raise Exception(operator, "Unknown operator")

# This function takes in a string representing a prefix equation to
#  evaluate and returns the result.  The equation's values and
#  operators are space delimited.
def calculate( equation ):
  # Gather the equation tokens
  tokens = equation.split( " " )

  # Initialize the evaluation stack.  This will contain the operators
  #  with index 0 always containing the next operator to utilize.  As
  #  values become available an operator will be removed and
  #  eval_expression called to calculate the result.
  eval_stack = [ ]
  total = None

  # Process all the equation tokens
  for token in tokens:
    if token.isdigit():
      # Save the first value.  Subsequent values trigger the evaluation
      #  of the next operator applied to the total and next values
      token = int(token)
      if total is None:
        total = token
      else:
        total = eval_expression(eval_stack.pop(0), total, token)

    else:
      # Save the new operator to the evaluation stack
      eval_stack.insert(0, token)

  # Done!  Provide the equation's value
  return total

# If running standalone pass the first command line parameter as
#  an expression and print the result.  Example:
#       python prefix.py "+ / 6 2 3 - 6"
if __name__ == '__main__':
  print calculate( sys.argv[1] )

这是我的想法。它保存了一堆操作符。当它收到足够的数字时,它弹出一个操作符并计算子表达式

#! /usr/bin/env python
from collections import deque
def parse(tokens):
    token=tokens.popleft()
    if token=='+':
            return parse(tokens)+parse(tokens)
    elif token=='-':
            return parse(tokens)-parse(tokens)
    elif token=='*':
            return parse(tokens)*parse(tokens)
    elif token=='/':
            return parse(tokens)/parse(tokens)
    else:
            # must be just a number
            return int(token)


if __name__=='__main__':
        expression="+ 2 2"
        print parse(deque(expression.split()))
# Bring in the system module to get command line parameters
import sys

# This function takes in some binary operator, which is just an arbitrary
#  string, and two values.  It looks up the method associated with the
#  operator, passes the two values into that method, and returns the
#  method's result.
def eval_expression(operator, value_one, value_two):
  if operator == "+":
    return value_one + value_two
  elif operator == "-":
    return value_one - value_two
  elif operator == "*":
    return value_one * value_two
  elif operator == "/":
    return value_one / value_two
  # Add new operators here.  For example a modulus operator could be
  #  created as follows:
  #       elif operator == "mod":
  #         return value_one % value_two
  else:
    raise Exception(operator, "Unknown operator")

# This function takes in a string representing a prefix equation to
#  evaluate and returns the result.  The equation's values and
#  operators are space delimited.
def calculate( equation ):
  # Gather the equation tokens
  tokens = equation.split( " " )

  # Initialize the evaluation stack.  This will contain the operators
  #  with index 0 always containing the next operator to utilize.  As
  #  values become available an operator will be removed and
  #  eval_expression called to calculate the result.
  eval_stack = [ ]
  total = None

  # Process all the equation tokens
  for token in tokens:
    if token.isdigit():
      # Save the first value.  Subsequent values trigger the evaluation
      #  of the next operator applied to the total and next values
      token = int(token)
      if total is None:
        total = token
      else:
        total = eval_expression(eval_stack.pop(0), total, token)

    else:
      # Save the new operator to the evaluation stack
      eval_stack.insert(0, token)

  # Done!  Provide the equation's value
  return total

# If running standalone pass the first command line parameter as
#  an expression and print the result.  Example:
#       python prefix.py "+ / 6 2 3 - 6"
if __name__ == '__main__':
  print calculate( sys.argv[1] )

我也喜欢MAK的递归函数。

反转令牌并使用如下所示的堆栈机:

def prefix_eval(tokens):
    stack = []
    for t in reversed(tokens):
        if   t == '+': stack[-2:] = [stack[-1] + stack[-2]]
        elif t == '-': stack[-2:] = [stack[-1] - stack[-2]]
        elif t == '*': stack[-2:] = [stack[-1] * stack[-2]]
        elif t == '/': stack[-2:] = [stack[-1] / stack[-2]]
        else: stack.append(t)
    assert len(stack) == 1, 'Malformed expression'
    return stack[0]

>>> prefix_eval(['+', 2, 2])
4
>>> prefix_eval(['-', '*', 3, 7, '/', 20, 4])
16
请注意,
stack[-1]
stack[-2]
与普通堆栈机器相反。这是为了适应这样一个事实,即它实际上是一个相反的前缀符号

我应该解释一下我使用过的几种Python习惯用法:

  • stack=[]
    :Python中没有内置的stack对象,但是列表很容易被用于相同的目的
  • 堆栈[-1]
    堆栈[-2]
    :Python支持负索引<代码>堆栈[-2]指的是列表的最后一个元素
  • stack[-2:][=…
    :除了负索引外,此赋值还结合了两种惯用法:
  • 切片:
    A[x:y]
    A
    x
    y
    的所有元素,包括
    x
    ,但不包括
    y
    (例如,A[3:5]指元素3和4)。省略的数字表示列表的开始或结束。因此,
    stack[-2::]
    引用从最后一个元素到列表末尾的每个元素,即最后两个元素
  • 切片分配:Python允许您分配一个切片,其效果是拼接一个新列表来代替切片所引用的元素
  • 把它们放在一起,
    stack[-2:][stack[-1]+stack[-2]]
    将堆栈的最后两个元素相加,从总和创建一个元素列表,并将该列表分配给包含两个数字的切片。最终的效果是将堆栈上最上面的两个数字替换为它们的和

    如果您想从字符串开始,一个简单的前端解析器将完成以下任务:

    def string_eval(expr):
        import re
        return prefix_eval([t if t in '+-*/' else int(t)
                            for t in re.split(r'\s+', expr)])
    
    >>> string_eval('/ 15 - 6 3')
    5
    

    基于其他答案,但逻辑性较低

    import operator
    
    def eval_prefix(tokens):
        operators = {'+': operator.add, '-': operator.sub, '/': operator.truediv, 
                     '*': operator.mul, '%': operator.mod}
    
        stack = []
        for i in reversed(tokens):
            if i in operators:
                stack[-2] = operators[i](int(stack[-1]), int(stack[-2]))
                del stack[-1]
            else:
                stack.append(i)
        return stack[0]
    

    下面是lambda函数的示例

    ops = {
      "+": (lambda a, b: a + b),
      "-": (lambda a, b: a - b),
      "*": (lambda a, b: a * b),
      "/": (lambda a, b: a / b)
    }
    
    def eval(expression):
      tokens = expression.split()
      stack = []
    
      for token in tokens:
        if token in ops:
          arg2 = stack.pop()
          arg1 = stack.pop()
          result = ops[token](arg1, arg2)
          stack.append(result)
        else:
          stack.append(int(token))
    
      return stack.pop()   
    

    这是另一种方法。我在a、b和c上添加了一个“@”开关,当a为正时返回b,当a为负时返回c。我知道它有点冗长,效率低下,但我希望它对所有操作都是通用的

    def operatorhelper(index, answer):
            del currentsplitline[index + 2]
            del currentsplitline[index + 1]
            del currentsplitline[index]
            currentsplitline.insert(index, answer)
        infilelines = ["+ 2 3", " - 3 2", "* 2 3", "@ 1 3 4"]
        for line in infilelines:
            currentsplitline = line.split(" ")
            for i in range(len(currentsplitline)):
                try:
                    currentsplitline[i] = int(currentsplitline[i])
                except:
                    continue
            operatorindexes = [int(i) for i,x in enumerate(currentsplitline) if not type(x) == int]
            operatorindexes = operatorindexes[::-1]
            for index in operatorindexes:
                answer = 0
                if(isinstance(currentsplitline[index + 1], int) and isinstance(currentsplitline[index + 2], int)):
                    operator = currentsplitline[index]
                    nextnum = currentsplitline[index + 1]
                    secondnum = currentsplitline[index + 2]
                    if(operator == "+"):
                        answer = nextnum + secondnum
                        operatorhelper(index, answer)
                    elif(operator == "-"):
                        answer = nextnum - secondnum
                        operatorhelper(index, answer)
                    elif(operator == "*"):
                        answer = nextnum * secondnum
                        operatorhelper(index, answer)
                    elif(operator == "@"):
                        if(isinstance(currentsplitline[index + 3], int)):
                            thirdnum = currentsplitline[index + 3]
                            del currentsplitline[index + 3]
                            if(nextnum >= 0):
                                answer = secondnum
                            else:
                                answer = thirdnum
                            operatorhelper(index, answer)
            print(currentsplitline[0])
    


    输入中有括号吗?写一个FORTH或PostScript解释器。。。或HP计算器仿真器…:-)我正在写一个简单的数学语言。输入示例如下:*0%5*1@2%7其中*0是基元“set”,%5告诉它设置数组中的第5个值,*1是“add”的基元,@2告诉它数组中的第二个位置。“我只是在学蟒蛇,”马塞洛说。chillax@kindall:这两个都是后缀。yyyyyyyyyeah,我是说LISP.:-)这不是一个真正的计算器,不适用于任意前缀表达式(请尝试
    ++2 4
    )。它只适用于最简单的表达式形式(即,只有一个运算符和两个数值参数)。我并不是说要编写一个完整的计算器,我只是严格地为他做了一些开始。这也不能验证整个表达式。如果要拆分的第二个和第三个标记不是数字,则它们将引发异常。假设它具有嵌套表达式,但采用我的代码格式*1*2%3%1%5将计算为(前缀):(+(-3 1)5)。。。那么我该如何解析它?@teknolagi:为什么前缀表达式中需要括号?评估的顺序是明确的。此代码应能与
    ++3 1 5
    配合使用。现在它只支持
    +
    ,但您可以轻松地为
    -
    和其他运算符添加大小写。@teknolagi:对其进行编辑,使其也适用于减法、乘法和除法。您的测试用例现在应该可以工作了。它验证您的整个表达式,以确保数字是数字,并且符号位于正确的位置。您选择的拆分方法不能保证表达式的格式正确。?我还是个初学者…什么是堆栈?那么令牌呢?@tekknolagi:tokens是解析器和编译器视为不可分割的源文本的小块。例如,在Python代码栈[-2:]=[stack[-1]+stack[-2]]中,令牌是:
    -
    -
    +
    堆栈
    [
    -
    2
    ]
    ]
    。请注意,原始表达式中的空格不会出现,因为它们仅用于分隔标记(在本例中实际上是多余的)。有些语言将
    -2
    视为单个标记,但更常见的是,它被解析为后跟非负整数的否定运算符。我能解释一下这段代码的作用吗?(初学者,这将是一个惊人的演练)查找递归,这段代码递归地计算您的数学表达式。它将不断地反复调用同一个函数,直到达到一个基本条件,使其返回一个实际值。一个非常优雅的解决方案。添加了一些注释。希望他们能帮助你。这不是使用递归。只是