Как разбить на токены выражение "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 шт):
Я немного изменил функцию. Попробуй такой вариант:
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']
В общем, я решил полностью отказаться от регулярных выражений и решил задачу с помощью алгоритма сортировочных станций. Мой код может быть далеко не идеальным и возможно считает не правильно, а в некоторых случаях может ломаться, но в моем проекте - калькуляторе я попробовал достаточно большое количество различных выражений со скобками, отрицательными числами и числами с плавающей точкой, различные комбинации и код ни разу не сломался.
Вот сам код токенизации выражения:
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