Тупой способ: использовать eval(), но
это очень рискованно! Если данные приходят извни, атакующий может вписать туда почти любой питоновский код. Потом не плачь, что тебя не предупреждали.
Умный способ, на примере
(-5 * 3) - 2
:
1. Разбить строку на осмысленные токены : число, оператор и т.п. Для каждого токена хранить его тип и значение. Получим список в духе:
[('parenthesis', '('), ('operator', '-'), ('number', '5'), ('operator', '*'), ('number', '3'), ('parenthesis', ')'), ('operator', '-'), ('number', '2') ]
Тут ушли все пробелы.
2. Подправить унарные операторы. Операторы "+" и "-", следующие за началом строки, открывающей скобкой или другим оператором, являются унарными (с одним аргументом), а не бинарными (с двумя). Их стоит обозначить по другому, чтобы не путать. Получим такое (смотри на второй токен):
[('parenthesis', '('), ('operator', 'unary-'), ('number', '5'), ('operator', '*'), ('number', '3'), ('parenthesis', ')'), ('operator', '-'), ('number', '2') ]
3. Преобразовать из инфиксной нотации (2 + 3) в постфиксную (2 3 +). Для этого есть железнодорожный алгоритм Дейкстры, он гуглится. В постфиксной нотации всё решается куда проще, так как ей не нужны скобки. Наш пример запишется как 5 unary- 3 * 2 -
[('number', '5'), ('operator', 'unary-'), ('number', '3'), ('operator', '*'), ('number', '2'), ('operator', '-')]
4. Решить пример. Алгоритм очень простой. У нас есть список аргументов, поначалу он пуст. Идём по списку токенов (в постфиксной нотации):
а. Если токен - число, поместить его в конец списка аргументов, перейти к следующему токену.
б. Если токен - унарный оператор, взять и удалить последний элемент из списка, применить к этому элементу оператор, результат добавить в конец списка.
в. Если токен - бинарный оператор, взять и удалить последние 2 элемента из списка, применить к ним оператор (не перепутай порядок аргументов!), результат добавить в конец списка.
Всё! Когда токены кончатся, у тебя в списке аргументов должно быть ровно одно число - это и будет ответ.
На нашем примере:
[('number', '5'), ('operator', 'unary-'), ('number', '3'), ('operator', '*'), ('number', '2'), ('operator', '-')]
1. Число "5": список аргументов [ 5 ]
2. Унарный минус: берем 5 из списка, применяем оператор, кладем результат назад. Список аргументов [ -5 ]
3. Число "3": список аргументов [ -5, 3 ]
4. Оператор *: берем -5 и 3 из списка, применяем оператор, кладём результат назад. Список аргументов [ -15 ]
5. Число "2": список аргументов [ -15, 2 ]
6. Бинарный минус: берем -15 и 2 из списка, применяем оператор, кладём результат назад. Список аргументов [ -17 ]
Токены закончились, в списке одно число -17. Это ответ.