Pythonic way to eval all octal values in a string as integers

白昼怎懂夜的黑 提交于 2019-12-10 03:57:56

问题


So I've got a string that looks like "012 + 2 - 01 + 24" for example. I want to be able to quickly (less code) evaluate that expression...

I could use eval() on the string, but I don't want 012 to be represented in octal form (10), I want it to be represented as an int (12).

My solution for this works, but it is not elegant. I am sort of assuming that there is a really good pythonic way to do this.

My solution:

#expression is some string that looks like "012 + 2 - 01 + 24"
atomlist = []
for atom in expression.split():
    if "+" not in atom and "-" not in atom:
        atomlist.append(int(atom))
    else:
        atomlist.append(atom)
#print atomlist
evalstring = ""
for atom in atomlist:
    evalstring+=str(atom)    
#print evalstring
num = eval(evalstring)

Basically, I tear appart the string, and find numbers in it and turn them into ints, and then I rebuild the string with the ints (essentially removing leading 0's except where 0 is a number on its own).

How can this be done better?


回答1:


I'd be tempted to use regular expressions to remove the leading zeroes:

>>> re.sub(r'\b0+(?!\b)', '', '012 + 2 + 0 - 01 + 204 - 0')
'12 + 2 + 0 - 1 + 204 - 0'

This removes zeroes at the start of every number, except when the number consists entirely of zeroes:

  • the first \b matches a word (token) boundary;
  • the 0+ matches one or more consecutive zeroes;
  • the (?!\b) (negative lookahead) inhibits matches where the sequence of zeroes is followed by a token boundary.

One advantage of this approach over split()-based alternatives is that it doesn't require spaces in order to work:

>>> re.sub(r'\b0+(?!\b)', '', '012+2+0-01+204-0')
'12+2+0-1+204-0'



回答2:


You can do this in one line using lstrip() to strip off any leading zeros:

>>> eval("".join(token.lstrip('0') for token in s.split()))
37



回答3:


I'd like to do it this way:

>>> s = '012 + 2 + 0 - 01 + 204 - 0'
>>> ' '.join(str(int(x)) if x.isdigit() else x for x in s.split())
'12 + 2 + 0 - 1 + 204 - 0'

Use float() if you want to handle them too :)




回答4:


int does not assume that a leading zero indicates an octal number:

In [26]: int('012')
Out[26]: 12

Accordingly, you can safely evalute the expression with the following code

from operator import add, sub
from collections import deque

def mapper(item, opmap = {'+': add, '-': sub}):
    try: return int(item)
    except ValueError: pass

    return opmap[item]

stack = deque()
# if item filters out empty strings between whitespace sequences
for item in (mapper(item) for item in "012 + 2 - 01 + 24".split(' ') if item):
    if stack and callable(stack[-1]):
        f = stack.pop()
        stack.append(f(stack.pop(), item))
    else: stack.append(item)

print stack.pop()

Not a one-liner, but it is safe, because you control all of the functions which can be executed.



来源:https://stackoverflow.com/questions/9843033/pythonic-way-to-eval-all-octal-values-in-a-string-as-integers

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!