2012-10-17 17 views
6

मैं अजगर का उपयोग कर स्प्रेडशीट xml से फ़ॉर्मूला संदर्भ मानचित्र बनाने पर काम कर रहा हूं। सूत्रपार्सिंग एक्सेल स्टाइल फॉर्मूला

=IF(AND(LEN(R[-2]C[-1])>0,R[-1]C),WriteCurve(OFFSET(R16C6, 0,0,R9C7,R10C7),R15C6,R10C3, R8C3),"NONE") 

मुझे केवल लिखने के कार्य की nth तर्क प्राप्त करने में रूचि है। यहां मैं बहुत सी शैली कार्यक्रम शुरू करता हूं जो मूल रूप से कोमा की गणना करता है जो ब्रैकेट के अंदर नहीं है। बहुत सारे नेस्टेड फॉर्मूला

def parseArguments(t, func, n): 
start=t.find(func)+len(func)+1 
bracket = 0 
ss = t[start:] 
lastcomma = 0 
for i, a in enumerate(ss): 
    if a=="(": 
     bracket +=1 
    elif a==")": 
     if bracket==0: 
      break 
     bracket-=1 
    elif a == ",": 
     if bracket==0 and n==0: 
      break 
     elif bracket ==0: 
      if n-1==0: 
       lastcomma = i 
      n-=1 
if lastcomma == 0: 
    return ss[:i] 
else: 
    return ss[lastcomma+1:i] 

क्या ऐसा करने का पाइथोनिक तरीका है? या पूरे सूत्र को पार्स करने के लिए एक बेहतर रिकर्सिव तरीका है? बहुत धन्यवाद

उत्तर

8

सबसे अच्छा एक्सेल फॉर्मूला पार्सर मुझे पता है कि E. W. Bachtal's algorithm है। रॉबिन माचर्ग द्वारा एक पायथन पोर्ट है; सबसे हालिया संस्करण जो मुझे पता है pycel project का हिस्सा है, लेकिन इसका उपयोग स्टैंडअलोन - tokenizer किया जा सकता है। है कि आपके फ़ार्मूले को पार्स कोई समस्या नहीं है:

from tokenizer import shunting_yard 
rpn = shunting_yard('=IF(AND(LEN(R[-2]C[-1])>0,R[-1]C),WriteCurve(OFFSET(R16C6, 0,0,R9C7,R10C7),R15C6,R10C3, R8C3),"NONE")') 
print(rpn) 
deque([<tokenizer.RangeNode object at 0x2b7b1f5d7850>, <tokenizer.FunctionNode object at 0x2b7b1f5d7950>, <tokenizer.ASTNode object at 0x2b7b1f5d7990>, <tokenizer.ASTNode object at 0x2b7b1f5d79d0>, <tokenizer.RangeNode object at 0x2b7b1f5d7a10>, <tokenizer.FunctionNode object at 0x2b7b1f5d7a50>, <tokenizer.RangeNode object at 0x2b7b1f5d7a90>, <tokenizer.ASTNode object at 0x2b7b1f5d7ad0>, <tokenizer.ASTNode object at 0x2b7b1f5d7b10>, <tokenizer.RangeNode object at 0x2b7b1f5d7b50>, <tokenizer.RangeNode object at 0x2b7b1f5d7b90>, <tokenizer.FunctionNode object at 0x2b7b1f5d7bd0>, <tokenizer.RangeNode object at 0x2b7b1f5d7c10>, <tokenizer.RangeNode object at 0x2b7b22efc450>, <tokenizer.RangeNode object at 0x2b7b22efc510>, <tokenizer.FunctionNode object at 0x2b7b22efc410>, <tokenizer.ASTNode object at 0x2b7b22eff110>, <tokenizer.FunctionNode object at 0x2b7b22eff150>]) 

tokenizer एक आरपीएन के साथ छोड़ देता है ढेर; यदि आप और अधिक सुविधाजनक एक एएसटी आप आसानी से एक एएसटी में बदल सकते हैं के साथ काम कर पाते हैं:

def rpn_to_ast(rpn): 
    stack = [] 
    for n in rpn: 
     num_args = (2 if n.token.ttype == "operator-infix" else 
        1 if n.token.ttype.startswith('operator') else 
        n.num_args if n.token.ttype == 'function' else 0) 
     n.args = [stack.pop() for _ in range(num_args)][::-1] 
     stack.append(n) 
    return stack[0] 

फिर आप WriteCurve नोड खोजने के लिए एएसटी चलना और अपने तर्कों की जांच कर सकते हैं:

def walk(ast): 
    yield ast 
    for arg in getattr(ast, 'args', []): 
     for node in walk(arg): 
      yield node 

write_curve = next(node for node in walk(rpn_to_ast(rpn)) if node.token.ttype == 'function' and node.token.tvalue == 'WriteCurve') 
print(write_curve.args[2].token.tvalue) 
R10C3 
संबंधित मुद्दे