2009-10-09 18 views
10

Qual è il modo migliore per implementare un programma python che prenderà una stringa e produrrà il risultato in base alla precedenza degli operatori (ad esempio: "4 + 3 * 5" restituirà 19). Ho cercato su Google modi per risolvere questo problema, ma erano tutti troppo complessi e sto cercando uno (relativamente) semplice.Valutazione Espressione matematica

chiarimento: ho bisogno di qualcosa di leggermente più avanzato di eval() - Voglio essere in grado di aggiungere altri operatori (ad esempio un operatore massimo - 4 $ 2 = 4) o, anche io sono più interessato a questo accademicamente che professionale - Voglio sapere come fare.

+1

http://docs.python.org/reference/simple_stmts.html#exec – nlucaroni

+1

Dai un'occhiata a: http: // stackoverflow.it/questions/400050/reading-and-running-a-espressione-matematica-in-python –

+1

Prova "valutare" invece di "risolvere" che suggerisce di essere in grado di trovare "x" dato "4x - 6 = 4". – dmckee

risposta

16

Se sei "accademicamente interessato", vuoi imparare come scrivere un parser con la precedenza degli operatori.

è un bell'articolo che crea un parser di esempio per fare esattamente ciò che si vuole fare: valutare espressioni matematiche.

Consiglio vivamente avendo un andare a scrivere il proprio primo parser - è uno di quei "ah, Ecco come funziona" momenti!

+0

Ho dato un'occhiata molto veloce, e sembra che l'articolo che hai collegato implementa il pattern Interpreter in Python. –

1

Non ho molta familiarità con Python e con qualsiasi metodo estremamente Pythonic, ma potreste vedere lo Interpreter pattern, che è definito nel libro Gang of Four. È progettato per l'elaborazione di un "linguaggio" e le espressioni matematiche seguono un particolare linguaggio con regole. In effetti, l'esempio su Wikipedia è in realtà un'implementazione Java di un calcolatore RPN.

+18

Così ora la loro chiamata analizza un "modello"? Questa deve essere la parola più abusata in informatica ... – Noldorin

+0

Non è solo parsing. Sta analizzando le "frasi" in un determinato "linguaggio" in modo pulito e comprensibile. –

+1

@Thomas: non è più specifico dell'analisi generica, davvero. Voglio dire, ogni parsing implica "frasi" di qualche tipo; e qualsiasi parser decente è pulito/comprensibile, almeno in qualche modo. (Vedere la discesa ricorsiva come esempio.) Inoltre, sono/sono/sono: P – Noldorin

1

Ecco cosa fa la funzione "eval" in Python.

result = eval(expression) 

Attenzione però può fare molto di più, soprattutto le funzioni di chiamata, in modo per essere sicuri è necessario assicurarsi che non può accedere ai locali o globali. Inoltre, è possibile accedere ai metodi incorporati, compresa la difficile importazione quindi è necessario bloccare l'accesso a quello pure:

result = eval(expression, {'__builtins__': None}, {}) 

Ma questo è solo se avete bisogno di sicurezza, vale a dire se si consente a chiunque di digitare qualsiasi espressione

Ovviamente, poiché in questo modo blocchi tutte le variabili locl dall'uso, non hai alcuna variabile da utilizzare, per cui devi passare solo quelle variabili a cui si deve accedere nei dizionari.

vars = {'__builtins__': None, 'x': x} 
result = eval(expression, vars, {}) 

o simile.

+1

Il problema con eval viene quando expression = "system.os (rm -rf \)". Se lo si esegue come root in * nix, boom passa alla macchina. O se è l'equivalente di Windows, soprattutto perché ci sono troppe persone che eseguono Windows come amministratore. –

+2

Solo se si è eseguito 'da sistema di importazione os' e non fornisce la directory globals e locals. Che faccio nei miei esempi per questo motivo. –

+0

All'interno dell'espressione, è possibile importare nuovamente il sistema da os e quindi utilizzarlo. Quindi sì, il mio esempio funzionerebbe solo se importassi già os dal sistema, ma espandendo la mia espressione, puoi importare tutto ciò che vuoi e usarlo. –

2

Un'altra possibilità è di guardare a Pyparsing, che è un generatore di parser generale. È più potente del necessario, ma potrebbe essere più veloce da implementare.

+0

Il wiki di pyparsing (pyparsing.wikispaces.com) include un paio di esempi di un parser di espressioni aritmetiche - fourFn.py e simpleArith.py. Anche se non si usa il pyparsing, fourFn.py rischia di essere illuminante nel modo in cui un parser implementa la precedenza degli operatori. – PaulMcG

+0

Ho appena realizzato che l'OP voleva aggiungere altri operatori. simpleArith.py mostra come aggiungere un operatore fattoriale (!) - evalArith.py (nella parte inferiore della pagina) espande simpleArith.py e mostra come valutare i valori analizzati. – PaulMcG

Problemi correlati