Pythonic way to evaluate all octal values ​​in a string as integers

So, I have a line that looks, for example, like "012 + 2 - 01 + 24" . I want to be able to quickly (less code) evaluate this expression ...

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

My solution for this works, but it is not elegant. I seem to suggest that there is a really good pythonic way to do this.

My decision:

 #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 spoil, add a string and find numbers in it and turn them into ints, and then I rebuild the string with ints (essentially removing the leading 0, except where 0 is a number on its own).

How can this be done better?

+6
source share
4 answers

I will be tempted to use regular expressions to remove leading zeros:

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

This removes zeros at the beginning of each number, unless the number consists entirely of zeros:

  • the first \b corresponds to the boundary of the word (token);
  • 0+ matches one or more consecutive zeros;
  • (?!\b) ( negative lookup ) prohibits matches where a sequence of zeros is followed by a border marker.

One of the advantages of this approach for split() -based alternatives is that no spaces are required for operation:

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

You can do this on one line using lstrip () to remove all leading zeros:

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

I would like to do it as follows:

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

+2
source

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

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

Accordingly, you can safely evaluate 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 one-line, but it is safe because you control all the functions that can be performed.

+1
source

Source: https://habr.com/ru/post/911517/


All Articles