[英]How to evaluate a custom math expression in Python
我在python中編寫了一個自定義骰子滾動解析器(如果必須,可以使用snicker)。 基本上,我想使用標准數學評估,但添加'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
我正在使用正則表達式來替換所有'和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)”失敗。
你可以使用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
Python不會讓你編寫全新的操作符,也不能用常規語言做括號。 你必須編寫一個遞歸下降解析器。 對於你的骰子滾動語言,這應該是非常簡單的。
或者,您可以使用現有的Python運算符並使用Pythons解析工具將文本轉換為AST。
這使用了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]))
是列表((random.randint(1,x) for x in [6,6,6,6]))
的生成器等價物; 這個特殊的將返回1到6之間的四個隨機數。
在我的Supybot骰子插件中,我解析表達式
r'(?P<sign>[+-])((?P<dice>\d*)d(?P<sides>\d+)|(?P<mod>\d+))'
然后得到每個骰子和總修飾符的總數,滾動它們並獲得總結果(我想顯示每個骰子的總數)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.