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

泄露秘密 提交于 2019-12-05 04:49:51

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'

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

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 :)

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.

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