0

I want to convert the string expression into a list without using built-in functions on Python and regex.

This is the example:

"(52^2)+150-(2^2+4+5)"

to:

["(", "52", "^", "2", ")", "+", "150", "-", "(", "2", "^", "2", "+", "4", "+", "5", ")"]

I used .split() but the number above 9 is separated.

Tomerikoo
  • 18,379
  • 16
  • 47
  • 61
delux
  • 45
  • 6
  • 1
    Do you have some constraints that prevent you from using regular expressions? Because that's most likely the best way to do it. – edornd Aug 18 '21 at 09:17
  • 1
    Looks like you want to write a lexer in Python. Without using any regex or built-ins this will be very difficult. Is there any particular reason you have to avoid these? I can also recommend [ply](https://www.dabeaz.com/ply/ply.html) for lexing. – L.Grozinger Aug 18 '21 at 09:17
  • I am creating a function that is equivalent to eval() and the approach that I used is to convert the expression to to list then evaluate the expression – delux Aug 18 '21 at 09:23

3 Answers3

7

You can do that using tokenize like so :

>>> from io import StringIO
>>> import tokenize

>>> formula = "(52^2)+150-(2^2+4+5)"
>>> print([token[1] for token in tokenize.generate_tokens(StringIO(formula).readline) if token[1]])
['(', '52', '^', '2', ')', '+', '150', '-', '(', '2', '^', '2', '+', '4', '+', '5', ')']
Holloway
  • 6,412
  • 1
  • 26
  • 33
tlentali
  • 3,407
  • 2
  • 14
  • 21
3

Just using plain python:

def fn(s):
    buf = ""
    for ch in s:
        if "0" <= ch <= "9":
            buf += ch
        else:
            if buf:
                yield buf
            yield ch
            buf = ""
    if buf:
        yield buf


print(list(fn("(52^2)+150-(2^2+4+5)")))

Prints:

['(', '52', '^', '2', ')', '+', '150', '-', '(', '2', '^', '2', '+', '4', '+', '5', ')']
Dharman
  • 30,962
  • 25
  • 85
  • 135
Andrej Kesely
  • 168,389
  • 15
  • 48
  • 91
  • I know that `yield` turns `fn(s)` into a generator, but what is its' added value instead of using `return`? – Rm4n Aug 18 '21 at 09:30
  • But what about if it is a negative number? – delux Aug 18 '21 at 09:43
  • 1
    @delux, use next condition `if "0" <= ch <= "9" or (not buf and ch == "-"):` or a bit shorter: `if "0" <= ch <= "9" or buf + ch == "-":` – Olvin Roght Aug 18 '21 at 09:53
  • @OlvinRoght, I have added your code and it is working but when I have an input like this "((9+3)-2)*5/1" and it becomes `['(', '(', '9', '+', '3', ')', '-2', ')', '*', '5', '/', '1']` how can I fix it? it becomes a negative number after parenthesis. – delux Aug 20 '21 at 03:21
  • @delux, check if "-" is a first symbol in string or there's another sign before it. It's barely possible with generator function, cause you have no access to previous output, but you might use some kind of flag which have to be set after any of signs returned. – Olvin Roght Aug 20 '21 at 08:59
  • 1
    @delux, something like [this](https://tio.run/##bZDPDoIwDMbvPEXtaRWJ/2KiRq4@gUcTg7LJEjKWDQ4@PXYYVNAelvT3tf262kddVGa9ta5tc6lAGeFpHwHHtVGQAmKXeH2/WFfdmJxcIzumKge3ArQB/@oIoRXgAuGQBolf3CFwnXgPyEwepJSlBOnT2FvGoXNAv7yPWenlW5ScDAewO88YshAPLcs8SNEvHbkNvv1nBd59wjq9CsaGH6PIOm1qMRWl9rXo7krdyXy4mEAhdvGakhVNN/MlzqAHPSGagZc2xbNBatsn). – Olvin Roght Aug 20 '21 at 09:14
1

If the numbers in the expressions are always integer, you can use the following code:

def to_list(text):
    lst = list(text)
    result = [lst[0]]
    for l in lst[1:]:
        if l.isnumeric() and result[-1].isnumeric():
            result[-1] += l
        else:
            result.append(l)
    return result
hochenri
  • 9
  • 2