2010-04-15 4 views
6

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

#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 на сумму, а затем используя eval, но мое регулярное выражение развалилось при работе с круглыми скобками любая сторона. Есть ли более быстрый способ сделать это, чем реализовать собственный рекурсивный синтаксический анализ? Возможно, добавив оператора в eval?

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

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)" не удается.

+0

Можете ли вы показать нам, что вы пробовали и как это не удалось? –

+0

Закончилось только выполнение рекурсивной вспомогательной функции. Спасибо за помощь! – taynaron

ответ

5

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

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

+0

Я думаю, что parens были просто демонстративным промежуточным результатом, а не частью самого DSL. Написание '1d6 + 2d6 + 2d6-72 + 4d100 = 84' не было бы все это объяснительным. Тем не менее, +1 для предложения о возвращении. –

+0

Тогда я смущен. Почему «регулярное выражение» OP [оспаривается отдельно при работе с круглыми скобками »? –

+1

Я был более расплывчатым, чем я думал, извините. Вышеприведенный пример отлично работает. Я имел в виду, что если вы поместите скобки по обе стороны от d (например, (4 + 2) d6), интерпретатор не сможет обработать это. – taynaron

6

Вы можете использовать callback function с re.sub. Когда вы по ссылке, поиск вплоть до пункта, начиная с «Если РЕПЛ функция ...»

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 
0

Это использует 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] - aвтоматическая карта - [6,6,6,6].

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

2

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

dice2.py

бросок костей анализатор и оценщик для оценки строк, таких как «4d20 + 5,5 + 4d6.takeHighest (3)» ,

0

В моих Supybot dice plugin я разобрать выражение с

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

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

Смежные вопросы