Как сделать математические операции со строкой? - PullRequest
1 голос
/ 21 октября 2019

Если есть строка calculation = '1+1x8'. Как я могу преобразовать это в calculation = 1+1*8? Я попытался сделать что-то вроде

for char in calculation:
    if char == 'x':
        calculation = calculation.replace('x', *)

    # and

    if char == '1':
        calculation = calculation.replace('1', 1)

Это явно не работает, так как вы не можете заменить только один символ целым числом. Вся строка должна быть целым числом, и если я это сделаю, она тоже не будет работать, поскольку я не могу преобразовать 'x' и '+' в целые числа

Ответы [ 3 ]

5 голосов
/ 21 октября 2019

Давайте используем более сложную строку в качестве примера: 1+12x8. То, что следует, является грубым планом;вам нужно предоставить реализацию для каждого шага.

Сначала вы токенизируете ее, превратив 1+12x8 в ['1', '+', '12', 'x', '8']. Для этого шага вам нужно написать токенизатор или лексический анализатор. На этом шаге вы определяете свои операторы и литералы.

Далее вы конвертируете поток токенов в дерево разбора. Возможно, вы представляете дерево как S-выражение ['+', '1', ['x', '12', '8']] или [operator.add, 1, [operator.mul, 12, 8]]. Этот шаг требует написания парсера, который требует от вас определения таких вещей, как приоритет ваших операторов.

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

  1. [operator.add, 1, [operator.mul, 12, 8]] до [operator.add, 1, 96]
  2. [operator.add, 1, 96] до 97
0 голосов
/ 21 октября 2019

Добавление кода к тому, что предложил Чепнер:

Токенизация '1 + 12x8' -> ['1', '+', '12', 'x', '8']. Используйте порядок операции '/ * + -' -> уменьшить вычисление 1 + (12 * 8) Вернуть ответ

import re
import operator




operators = {
        '/': operator.truediv,
        'x':operator.mul,
        '+':operator.add,
        '-':operator.sub,

    }

def op(operators, data):
    # apply operating to all occurrences 

    for p in operators:
        while p in data:
            x = data.index(p)
            replacer = operators.get(p)(int(data[x-1]) , int(data[x+1]))
            data[x-1] = replacer
            del data[x:x+2]


    return data[0]


def func(data):
    # Tokenize

    d = [i for i in re.split('(\d+)', data) if i ]

    # Use order of operations 
    d = op(operators, d)

    return d


s1 = "1+1x8"
s2 = '2-4/2+5'


s = func(s1) # 9
print(s)

t = func(s2) #-5
print(t)
0 голосов
/ 21 октября 2019

Вы можете написать что-то вроде:

def parse_exp(s):
    return eval(s.replace('x','*'))

и расширить для любых других экзотических символов, которые вы хотите использовать.

Чтобы ограничить риски, связанные с eval, вы также можете устранить плохие символы:

import string

good = string.digits + '()/*+-x'

def parse_exp(s):
    s2 = ''.join([i for i in s if i in good])
    return eval(s2.replace('x','*'))

Редактировать: дополнительный бонус заключается в том, что встроенная функция eval будет заботиться о таких вещах, как скобки и общие правила вычислений:)

Редактировать 2: Как отметил другой пользователь,eval может быть опасно . Поэтому используйте его только в том случае, если ваш код будет выполняться только локально

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...