Pythonic способ оценить все восьмеричные значения в строке как целые числа - PullRequest
6 голосов
/ 23 марта 2012

Итак, у меня есть строка, которая выглядит, например, как "012 + 2 - 01 + 24".Я хочу иметь возможность быстро (меньше кода) оценить это выражение ...

Я мог бы использовать eval () для строки, но я не хочу, чтобы 012 было представлено в восьмеричной форме (10), Я хочу, чтобы он был представлен как int (12).

Мое решение для этого работает, но оно не элегантно.Я как бы предполагаю, что есть действительно хороший питонский способ сделать это.

Мое решение:

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

По сути, я разрываю аппроксимацию строки и нахожу в ней числа и переворачиваюих в целые числа, а затем я перестраиваю строку с помощью целых чисел (по сути, удаляя начальные 0, кроме тех случаев, когда 0 - это само по себе число).

Как это можно сделать лучше?

Ответы [ 4 ]

9 голосов
/ 23 марта 2012

Я хотел бы использовать регулярные выражения для удаления начальных нулей:

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

Это удаляет нули в начале каждого числа, кроме случаев, когда число полностью состоит из нулей:

  • первый \b соответствует границе слова (токена);
  • 0+ соответствует одному или нескольким последовательным нулям;
  • (?!\b) ( отрицательный прогноз ) запрещает совпадения, когда после последовательности нулей следует граница токена.

Одним из преимуществ этого подхода перед split() альтернативами является то, что для его работы не требуются пробелы:

>>> re.sub(r'\b0+(?!\b)', '', '012+2+0-01+204-0')
'12+2+0-1+204-0'
5 голосов
/ 23 марта 2012

Вы можете сделать это в одну строку, используя lstrip () для удаления любых начальных нулей:

>>> eval("".join(token.lstrip('0') for token in s.split()))
37
2 голосов
/ 23 марта 2012

Я бы хотел сделать это следующим образом:

>>> 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'

Используйте float(), если вы хотите обрабатывать их тоже:)

1 голос
/ 23 марта 2012

int не предполагает, что начальный ноль обозначает восьмеричное число:

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

Соответственно, вы можете безопасно вычислить выражение с помощью следующего кода

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

Не однострочник, но это безопасно, потому что вы управляете всеми функциями, которые могут быть выполнены.

...