Как оценить пользовательское математическое выражение в Python

Я пишу пользовательский синтаксический анализатор прокрутки игры в кости (хихиканье, если Вы должны) в Python. В основном я хочу использовать стандартную математическую оценку, но добавить 'd' оператор:

#xdy
sum = 0
for each in range(x):
    sum += randInt(1, y)
return sum

Так, чтобы, например, 1d6+2d6+2d6-72+4d100 = (5) + (1+1) + (6+2)-72 + (5+39+38+59) = 84

Я использовал regex для замены всего 'd's суммой и затем использовал оценку, но мой regex развалился при контакте с круглыми скобками с обеих сторон. Существует ли более быстрый способ пойти об этом, чем реализация моего собственного рекурсивного парсинга? Возможно, добавляя оператор к оценке?

Править: Я, кажется, дал плохой пример, поскольку вышеупомянутый пример работает с моей текущей версией. То, что я ищу, является некоторым способом оценить, скажем, (5 + (6d6)) d (7-2* (1d4)).
"Развалился", я просто подразумевал, что мое текущее regex выражение перестало работать. Я был слишком неопределенен о своем отказе, извините для беспорядка. Вот мой текущий код:

def evalDice(roll_matchgroup):
    roll_split = roll_matchgroup.group('roll').split('d')
    print roll_split
    roll_list = []

    for die in range(int(roll_split[0])):
        roll = random.randint(1,int(roll_split[1]))
        roll_list.append(roll)

def EvalRoll(roll):
    if not roll: return 0
    rollPattern = re.compile('(?P<roll>\d*d\d+)')
    roll_string = rollPattern.sub(evalDice, roll.lower())

для этого, "1d6+4d100" работает просто великолепно, но" (1d6+4) d100" или даже "1d6+4d (100)" сбои.

6
задан taynaron 15 April 2010 в 04:52
поделиться

5 ответов

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

В качестве альтернативы вы можете использовать существующий оператор Python и использовать инструменты синтаксического анализа Pythons для преобразования текста в AST.

5
ответ дан 8 December 2019 в 18:34
поделиться

Взгляните на библиотеку PyParsing . В частности, на странице examples есть пример , довольно близкий к тому, что вы хотите:

dice2.py

Анализатор и вычислитель броска кости для оценки строк, таких как «4d20 + 5.5 + 4d6.takeHighest (3) ".

2
ответ дан 8 December 2019 в 18:34
поделиться

Вы можете использовать функцию обратного вызова с re.sub . Когда вы переходите по ссылке, ищите до абзаца, начинающегося с «Если repl - это функция ...»

import re
import random

def xdy(matchobj):
    x,y=map(int,matchobj.groups())
    s = 0
    for each in range(x):
        s += random.randint(1, y)
    return str(s)
s='1d6+2d6+2d6-72+4d100'
t=re.sub('(\d+)d(\d+)',xdy,s)
print(t)
# 5+10+8-72+197
print(eval(t))
# 148
6
ответ дан 8 December 2019 в 18:34
поделиться

Здесь используется eval, что на самом деле довольно ужасно, но вот и все.

>>> x = '1d6+2d6+2d6-72+4d100'
>>> eval(re.sub(r'(\d+)d(\d+)',r'sum((random.randint(1,x) for x in \1 * [\2]))', x))

Небольшие заметки:

Это заменяет, скажем, 4d6 на sum ((random.randint (1, x) for x in 4 * [6])) .

4 * [6] дает список [6,6,6,6] .

((random.randint (1, x) for x in [6,6,6,6])) - генератор, эквивалентный пониманию списка; этот конкретный вернет четыре случайных числа от 1 до 6.

0
ответ дан 8 December 2019 в 18:34
поделиться

В моем плагине Supybot dice я анализирую выражение с помощью

r'(?P<sign>[+-])((?P<dice>\d*)d(?P<sides>\d+)|(?P<mod>\d+))'

, затем получаю общее количество каждой кости и общий модификатор, бросаю их и получаю общий результат (я хотел показать общее количество каждой кости ).

0
ответ дан 8 December 2019 в 18:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: