Вопрос по регулярным выражениям на Python

В этом задании нужно написать программу, которая найдет в тексте ряд простых арифметических выражений и подсчитает их.

Любое выражение начинается с имени переменной a, b или c, затем может идти + или -, затем идет =, затем может идти имя переменной a, b или c, а затем может идти + или - и целое число. Если в правой части выражения нет переменной, то число может быть без знака + или -

Не бывает названий переменных, кроме a, b или c, и действий, кроме описанных тут. Не бывает пробелов вокруг знаков. В тексте не встречаются некорректные выражения, в которых справа от = нет ни переменной, ни числа. Таким образом, список типов выражений, которые могут встречаться, выглядит примерно так:

a=1, a=+1, a=-1, a=b, a=b+100, a=b-100, b+=10, b+=+10, b+=-10, b+=b, b+=b+100, b+=b-100, c-=101, c-=+101, c-=-101, c-=b, c-=b+101, c-=b-101

Выражения могут встречаться внутри текста, например loremc-=a+10ipsuma-=adb+=10olorsitamet.

В вашу функцию calculate(data, findall) будет передан словарь с начальными значениями переменных a, b и c: data = {"a":1, "b":2, "c": 3} и ссылка на функцию findall, а вы должны вернуть такой же словарь с новыми значениями для a, b и c.

Работает findall() аналогично re.findall(), только у нее всего один параметр – регулярное выражение. А текст, в котором она будет искать выражения, она знает сама (см. приложенный архив, чтобы понять, о чем речь). С помощью findall() нужно как минимум найти все выражения в тексте, а как максимум найти их и разбить на группы так, чтобы было удобно их обработать. Если findall() будет вызвано больше одного раза или если размер списка, который она вернет, будет отличаться от количества выражений в тексте, тест провалится.

Эталонное решение занимает 11 строк, не содержит импортов, не использует eval, а регулярное выражение находит выражения и бьет каждое на четыре группы (некоторые группы для некоторых выражений оказываются пустыми):

Имя переменной слева. Знак перед = (если есть). Имя переменной справа (если есть). Число (если есть) со знаком (если есть). Это позволяет легко (буквально в одну строку) посчитать правую часть, а потом, в зависимости от наличия знака перед =, произвести действие с левой частью. Однако ваш алгоритм может быть другим, требуется только выполнить ограничения на вызов findall() и оставить сигнатуру calculate() неизменной.

Нужно переписать функцию calculate() внутри шаблона:

def calculate(data, findall):
    matches = findall(r"")  # Если придумать хорошую регулярку, будет просто
    for v1, s, v2, n in matches:  # Если кортеж такой структуры: var1, [sign]=, [var2], [[+-]number]
        # Если бы могло быть только =, вообще одной строкой все считалось бы, вот так:
        data[v1] = data.get(v2, 0) + int(n or 0)
    return data

Для проверки решения локально запустите:

import re
from regexp import calculate

def findall(regexp):
    text = """
    a=1
    a=+1
    a=-1
    a=b
    a=b+100
    a=b-100
    
    b+=10
    b+=+10
    b+=-10
    b+=b
    b+=b+100
    b+=b-100
    
    c-=101
    c-=+101
    c-=-101
    c-=b
    c-=b+101
    c-=b-101
    """
    return re.findall(regexp, text)

result = calculate({'a': 1, 'b': 2, 'c': 3}, findall)
correct = {"a": -98, "b": 196, "c": -686}
if result == correct:
    print ("Correct")
else:
    print ("Incorrect: %s != %s" % (result, correct))

Есть вариант, который уже отправлял на проверку, но система его не принимает. Вот он:

data = {"a":1, "b":2, "c": 3}

def calculate(data):
    matches = re.findall(r"([abc])([+-]?=)([abc])?([+-]?\d+)?",text)
    for v1, s, v2, n in matches:
        if n == "":
            n = 0
        if s == "=" and v2 == "":
            data[v1] = int(n)
        elif s == "=" and v2 != "":
            data[v1] = data[v2] + int(n)
            print("eee")
        elif s == "+=" and v2 == "":
            data[v1] += int(n)
        elif s == "+=" and v2 != "":
            data[v1] += data[v2] + int(n)
        elif s == "-=" and v2 == "":
            data[v1] -= int(n)
        elif s == "-=" and v2 != "":
            data[v1] -= data[v2] + int(n)
    return data

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