2011-07-14 16 views
8

मैं वर्तमान में जावा से पायथन तक संक्रमण कर रहा हूं और एक कैलकुलेटर बनाने की कोशिश करने के कार्य को ले लिया है जो सिम्पी जैसे कस्टम मॉड्यूल का उपयोग किये बिना इंफिक्स-नोटेड गणितीय अभिव्यक्तियों () पर प्रतीकात्मक संचालन कर सकता है। वर्तमान में, यह उन तारों को स्वीकार करने के लिए बनाया गया है जो अंतरिक्ष सीमित हैं और केवल (,), +, -, *, और/ऑपरेटरों को ही कर सकते हैं। दुर्भाग्य से, मैं प्रतीकात्मक अभिव्यक्ति को सरल बनाने के लिए मूल एल्गोरिदम नहीं समझ सकता।मैं एक समारोह अजगर 2.7 में प्रतीकात्मक गणना किया जाता है कि लिख सकते हैं?

उदाहरण के लिए

, स्ट्रिंग '2 * ((9/6) + 6 * x)', मेरे कार्यक्रम के लिए निम्न चरणों को पूरा करना चाहिए दिया:

  1. 2 * (1,5 + 6 * x)
  2. 3 + 12 * एक्स

लेकिन जब 2. इसके अलावा वितरण मैं इस कार्यक्रम एक्स अनदेखी करने के लिए नहीं मिल सकता है, मैं कैसे संभाल कर सकते हैं 'एक्स * 6/एक्स' तो यह रिटर्न ' 6 'सरलीकरण के बाद?

संपादित करें: "प्रतीकात्मक" द्वारा स्पष्ट करने के लिए मेरा मतलब था कि यह शेष गणना करने के दौरान आउटपुट में "ए" और "एफ" जैसे अक्षरों को छोड़ देगा।

संपादित करें 2: मैं (अधिकतर) कोड समाप्त हो गया। अगर मैं भविष्य में इस पोस्ट पर ठोकर खा रहा हूं, या आप में से कोई भी उत्सुक था, तो मैं इसे यहां पोस्ट कर रहा हूं।

def reduceExpr(useArray): 

     # Use Python's native eval() to compute if no letters are detected. 
     if (not hasLetters(useArray)): 
      return [calculate(useArray)] # Different from eval() because it returns string version of result 

     # Base case. Returns useArray if the list size is 1 (i.e., it contains one string). 
     if (len(useArray) == 1): 
      return useArray 

     # Base case. Returns the space-joined elements of useArray as a list with one string. 
     if (len(useArray) == 3): 
      return [' '.join(useArray)] 

     # Checks to see if parentheses are present in the expression & sets. 
     # Counts number of parentheses & keeps track of first (found. 
     parentheses = 0 
     leftIdx = -1 

     # This try/except block is essentially an if/else block. Since useArray.index('(') triggers a KeyError 
     # if it can't find '(' in useArray, the next line is not carried out, and parentheses is not incremented. 
     try: 
      leftIdx = useArray.index('(') 
      parentheses += 1 
     except Exception: 
      pass 

     # If a KeyError was returned, leftIdx = -1 and rightIdx = parentheses = 0. 
     rightIdx = leftIdx + 1 

     while (parentheses > 0): 
      if (useArray[rightIdx] == '('): 
       parentheses += 1 
      elif (useArray[rightIdx] == ')'): 
       parentheses -= 1 
      rightIdx += 1 

     # Provided parentheses pair isn't empty, runs contents through again; else, removes the parentheses 
     if (leftIdx > -1 and rightIdx - leftIdx > 2): 
      return reduceExpr(useArray[:leftIdx] + [' '.join(['(',reduceExpr(useArray[leftIdx+1:rightIdx-1])[0],')'])] + useArray[rightIdx:]) 
     elif (leftIdx > -1): 
      return reduceExpr(useArray[:leftIdx] + useArray[rightIdx:]) 

     # If operator is + or -, hold the first two elements and process the rest of the list first 
     if isAddSub(useArray[1]): 
      return reduceExpr(useArray[:2] + reduceExpr(useArray[2:])) 
     # Else, if operator is * or /, process the first 3 elements first, then the rest of the list 
     elif isMultDiv(useArray[1]): 
      return reduceExpr(reduceExpr(useArray[:3]) + useArray[3:]) 
     # Just placed this so the compiler wouldn't complain that the function had no return (since this was called by yet another function). 
     return None 
+8

मुझे लगता है कि आप Sympy के आधार पर देखने के लिए :-) मुझे लगता है कि आप, गणित भाव के लिए एक पूर्ण पुनरावर्ती वंश पार्सर के निर्माण पर देख रहे हैं के लिए हल करने के लिए डेटा पेड़ के हेरफेर के बाद शुरू कर रहे हैं एक्स – wberry

+0

हाँ !!! आप कर सकते हैं;) – Drakosha

+0

@ li.davidm यह अभी भी तर्क चरणों में है। मैं समझ नहीं सकता कि पहले ठोकरें ब्लॉक को कैसे कार्यान्वित किया जाए। – Edwin

उत्तर

4

आपको प्रतीकों पर संचालन में जाने से पहले आपको और अधिक प्रोसेसिंग की आवश्यकता है। जिस रूप में आप प्राप्त करना चाहते हैं वह पत्ती नोड्स में मूल्यों के साथ संचालन का वृक्ष है। यदि आप हमेशा अंतरिक्ष अलग तत्व यह पर्याप्त हो सकता है, हालांकि सिर्फ स्ट्रिंग विभाजित करने के लिए - सबसे पहले आप तत्वों पाने के लिए स्ट्रिंग पर एक lexer रन की ज़रूरत है। फिर आपको आवश्यक कुछ व्याकरण का उपयोग करके टोकन की उस सरणी को पार्स करने की आवश्यकता है।

आप व्याकरण और पार्स पाठ के बारे में सैद्धांतिक जानकारी की जरूरत है, यहाँ शुरू: http://en.wikipedia.org/wiki/Parsing आप और अधिक व्यावहारिक कुछ की जरूरत है, http://pyparsing.wikispaces.com/Documentation के पास जाओ (आप pyparsing मॉड्यूल में ही उपयोग करने के लिए नहीं है, लेकिन उनके प्रलेखन दिलचस्प का एक बहुत है जानकारी) या http://www.nltk.org/book

2 * ((9/6) + 6 * x) से, आप इस तरह एक पेड़ से प्राप्त करने की आवश्यकता:

 * 
2   + 
     / * 
     9 6 6 x 

तो फिर तुम प्रत्येक नोड पर जाएँ और यदि आप इसे आसान बनाने के लिए चाहते तय कर सकते हैं। निरंतर संचालन खत्म करने के लिए सबसे सरल होंगे - केवल परिणाम की गणना करें और "/" नोड को 1.5 के साथ एक्सचेंज करें क्योंकि सभी बच्चे स्थिर हैं।

जारी रखने के लिए कई रणनीतियों रहे हैं, लेकिन अनिवार्य रूप से आप कुछ भी नहीं बदलने के लिए छोड़ दिया है जब तक पेड़ के माध्यम से जाना है और इसे संशोधित करने के लिए एक रास्ता खोजने की जरूरत है।

आप तो परिणाम मुद्रित करने के लिए, बस फिर पेड़ चलना और एक अभिव्यक्ति है जो यह बताता है उत्पादन चाहते हैं।

+0

ओह, तो वही है जो वाबेरी कहने की कोशिश कर रहा था। इसे स्पष्ट करने के लिए धन्यवाद, और खेद है कि मैं अभी आपके उत्तर को ऊपर नहीं उठा सकता। (हालांकि मैं एक बार सही हो जाऊंगा।) – Edwin

2

यदि आप पाइथन में अभिव्यक्तियों को पार्स कर रहे हैं, तो आप अभिव्यक्तियों के लिए पायथन वाक्यविन्यास पर विचार कर सकते हैं और उन्हें ast module (एएसटी = अमूर्त वाक्यविन्यास पेड़) का उपयोग करके पार्स कर सकते हैं।

अजगर सिंटेक्स के उपयोग के फायदे: आप इस प्रयोजन के लिए एक अलग भाषा बनाने के लिए नहीं है, पार्सर में बनाया गया है, और इसलिए मूल्यांकनकर्ता है।नुकसान: पार्स पेड़ में बहुत अधिक जटिलता है जिसकी आपको आवश्यकता नहीं है (आप अपने काम करने के लिए निर्मित NodeVisitor और NodeTransformer कक्षाओं का उपयोग करके इसमें से कुछ से बच सकते हैं)।

>>> import ast 
>>> a = ast.parse('x**2 + x', mode='eval') 
>>> ast.dump(a) 
"Expression(body=BinOp(left=BinOp(left=Name(id='x', ctx=Load()), op=Pow(), 
right=Num(n=2)), op=Add(), right=Name(id='x', ctx=Load())))" 

यहाँ एक उदाहरण वर्ग है कि एक अजगर पार्स पेड़ चलता है और (बाइनरी के संचालन के लिए) पुनरावर्ती निरंतर तह करता है, तो आप बात आप काफी आसानी से कर सकते हैं की तरह दिखाने के लिए।

from ast import * 

class FoldConstants(NodeTransformer): 
    def visit_BinOp(self, node): 
     self.generic_visit(node) 
     if isinstance(node.left, Num) and isinstance(node.right, Num): 
      expr = copy_location(Expression(node), node) 
      value = eval(compile(expr, '<string>', 'eval')) 
      return copy_location(Num(value), node) 
     else: 
      return node 

>>> ast.dump(FoldConstants().visit(ast.parse('3**2 - 5 + x', mode='eval'))) 
"Expression(body=BinOp(left=Num(n=4), op=Add(), right=Name(id='x', ctx=Load())))" 
संबंधित मुद्दे