Как разбить на токены выражение "5/-4" и "5*-4" Python

У меня есть функция - токенизатор, которая преобразовывает в токены математическое выражение.

Токенизатор:

def tokenization(expr):
    tokens = re.findall(r'\d+\.\d+|\d+|[()+\-*/]', expr)
    return tokens

Если в эту функцию загрузить строку "5/-4" или "5*-4", то в ответ мы получим:

Input: 5/-4

Output: ["5", "/", "-", "4"]

Ожидаемый результат: ["5", "/", "-4"]

Аналогично с умножением:

Input: 5*-4

Output: ["5", "*", "-", "4"]

Ожидаемый результат: ["5", "*", "-4"]

Как сделать так, чтобы токенизатор выдавал лист, который я описал в ожидаемом результате?


Ответы (2 шт):

Автор решения: Kirill Kondratenko

Я немного изменил функцию. Попробуй такой вариант:

def tokenization(expr):
    tokens = re.findall(r'[()\*/]|-?\d+\.?\d*|\d+|[()\-*/]', expr)
    return tokens

Пример 1:

tokenization("5/-4")
>>['5', '/', '-4']

Пример 2:

tokenization("5*-4")
>>['5', '*', '-4']
→ Ссылка
Автор решения: Fraz

В общем, я решил полностью отказаться от регулярных выражений и решил задачу с помощью алгоритма сортировочных станций. Мой код может быть далеко не идеальным и возможно считает не правильно, а в некоторых случаях может ломаться, но в моем проекте - калькуляторе я попробовал достаточно большое количество различных выражений со скобками, отрицательными числами и числами с плавающей точкой, различные комбинации и код ни разу не сломался.

Вот сам код токенизации выражения:

def tokenization(expression):
    """Разбивка мат. выражения на токены"""

    tokens = []
    i = 0 # Индекс элемента в выражении
    temp_token = "" # Если встречается 2 мат. оператора подряд ( наприм. 1*-1), то хранит последний

    if expression[0] in '/*-+':
        expression = "0" + expression

    while i < len(expression):
        # Если символ - цифра или точка, то добавляем его в токен и в цикле перебираем следующие символы
        if expression[i].isdigit() or expression[i] == '.':
            num_token = []

            # Если в temp_token больше 2 мат. операторов - Ошибка
            if len(temp_token) > 1:
                raise ValueError("Error: Ошибка в выражении!")

            # Если в temp_token есть оператор, то прибавить его к началу будущего числа
            elif temp_token:
                num_token.append(temp_token)
                temp_token = ""

            # Перебираем и добавляем следующие символы в токен до первого не-числа и не-точки.
            while i < len(expression) and (expression[i].isdigit() or expression[i] == '.'):
                num_token.append(expression[i])
                i += 1
            tokens.append("".join(num_token))

         # Если символ - оператор, то смотрим, какие символы идут после него
        elif expression[i] in '/*-+':
            op_token = []
            while i < len(expression) and expression[i] in "/*-+":
                if expression[i - 1] == '(':
                    tokens.append('0')
                op_token.append(expression[i])
                i += 1

            if len(op_token) > 1:
                temp_token = "".join(op_token[1:])
                op_token = op_token[0]
            tokens.append("".join(op_token))

        # Если символ - скобка, то добавляем его как отдельный токен
        elif expression[i] in '()':
            while i < len(expression) and expression[i] in "()":
                tokens.append(expression[i])
                i += 1

        # Иначе пропускаем символ
        else:
            i += 1
    return tokens
→ Ссылка