2016-06-20 5 views
1

Ich benutze pyparsing (2.1.5) auf Python 3.5.0. Ich möchte InfixNotation schneller machen. Ich habe festgestellt, dass andere Personen ParserElement.enablePackrat() zur Verbesserung der Leistung von infixNotation verwendet haben. Aber ich kann es nicht schaffen. Mein Code ist folgt.ParserElement.enablePackrat() macht infixNotation nicht schneller

from pyparsing import * 
ParserElement.enablePackrat() 
UNICODE_CHARS = u''.join(
    chr(c) for c in range(65538) if not chr(c).isspace() and 
    chr(c) not in '()"' 
) 
_and_ = Keyword('AND') 
_or_ = Keyword('OR') 
_not_ = Keyword('NOT') 
search_term = ~_and_ + ~_or_ + ~_not_ + Word(UNICODE_CHARS) | QuotedString(
    '"', endQuoteChar='"', unquoteResults=False 
) 
search_expr = infixNotation(
    search_term, 
    [ 
     (_not_, 1, opAssoc.RIGHT), 
     (Optional(_and_), 2, opAssoc.LEFT), 
     (_or_, 2, opAssoc.LEFT), 
    ] 
) 
parsed_query = search_expr.parseString(user_string)[0].asList() 

Antwort

0

Diese Verwendung von infixNotation hat nur 3 Ebenen der Betreiber, so packratting wird für Sie nicht viel tun. Die Verbesserungen sind normalerweise mit 5 oder mehr Ebenen von Operatoren, wie etwa mit arithmetischen Operationen.

Wenn Sie wirklich versuchen, die Leistung Kurbel aus infixNotation, schreiben Sie Ihre eigene abgespeckte Version:

""" 
BNF 

operand = ~and ~or ~not (A-Za-z0-9)... | quoted_string 

atom = 'not'? (operand | '(' expr ')') 
and_term = atom 'and' atom 
or_term = and_term 'or' and_term 
""" 


_and_ = CaselessKeyword('AND') 
_or_ = CaselessKeyword('OR') 
_not_ = CaselessKeyword('NOT') 
keyword = (_and_ | _or_ | _not_) 
search_term = ~keyword + Word(UNICODE_CHARS) | QuotedString('"', endQuoteChar='"', unquoteResults=False) 

# use this instead of infixNotation - this is essentially what infixNotation will 
# generate, but with fewer FollowedBy's (used to collapse degenerate levels) 
LPAR,RPAR = map(Suppress, "()") 
expr = Forward() 
atom_ = search_term | Group(LPAR + expr + RPAR) 
atom = Group(_not_ + atom_) | atom_ 
and_term = Group(atom + ZeroOrMore(_and_ + atom)) 
or_term = Group(and_term + ZeroOrMore(_or_ + and_term)) 
expr <<= or_term 

# some simple test cases 
tests = """ 
    p and not q 
    p and not q or r 
    p and not (q or r) 
""" 

print("compare with using infixNotation") 
expr.runTests(tests) 

print("compare with using infixNotation") 
search_expr = infixNotation(
    search_term, 
    [ 
     (_not_, 1, opAssoc.RIGHT), 
     (Optional(_and_), 2, opAssoc.LEFT), 
     (_or_, 2, opAssoc.LEFT), 
    ] 
) 

search_expr.runTests(tests) 

Die hartcodierte Version ausgegeben geben wie:

p and not q 
[[['p', 'AND', ['NOT', 'q']]]] 
[0]: 
    [['p', 'AND', ['NOT', 'q']]] 
    [0]: 
    ['p', 'AND', ['NOT', 'q']] 
    [0]: 
     p 
    [1]: 
     AND 
    [2]: 
     ['NOT', 'q'] 


p and not q or r 
[[['p', 'AND', ['NOT', 'q']], 'OR', ['r']]] 
[0]: 
    [['p', 'AND', ['NOT', 'q']], 'OR', ['r']] 
    [0]: 
    ['p', 'AND', ['NOT', 'q']] 
    [0]: 
     p 
    [1]: 
     AND 
    [2]: 
     ['NOT', 'q'] 
    [1]: 
    OR 
    [2]: 
    ['r'] 


p and not (q or r) 
[[['p', 'AND', ['NOT', [[['q'], 'OR', ['r']]]]]]] 
[0]: 
    [['p', 'AND', ['NOT', [[['q'], 'OR', ['r']]]]]] 
    [0]: 
    ['p', 'AND', ['NOT', [[['q'], 'OR', ['r']]]]] 
    [0]: 
     p 
    [1]: 
     AND 
    [2]: 
     ['NOT', [[['q'], 'OR', ['r']]]] 
     [0]: 
     NOT 
     [1]: 
     [[['q'], 'OR', ['r']]] 
     [0]: 
      [['q'], 'OR', ['r']] 
      [0]: 
      ['q'] 
      [1]: 
      OR 
      [2]: 
      ['r'] 

Infixnotation Verwendung wird geben:

p and not q 
[['p', 'AND', ['NOT', 'q']]] 
[0]: 
    ['p', 'AND', ['NOT', 'q']] 
    [0]: 
    p 
    [1]: 
    AND 
    [2]: 
    ['NOT', 'q'] 


p and not q or r 
[[['p', 'AND', ['NOT', 'q']], 'OR', 'r']] 
[0]: 
    [['p', 'AND', ['NOT', 'q']], 'OR', 'r'] 
    [0]: 
    ['p', 'AND', ['NOT', 'q']] 
    [0]: 
     p 
    [1]: 
     AND 
    [2]: 
     ['NOT', 'q'] 
    [1]: 
    OR 
    [2]: 
    r 


p and not (q or r) 
[['p', 'AND', ['NOT', ['q', 'OR', 'r']]]] 
[0]: 
    ['p', 'AND', ['NOT', ['q', 'OR', 'r']]] 
    [0]: 
    p 
    [1]: 
    AND 
    [2]: 
    ['NOT', ['q', 'OR', 'r']] 
    [0]: 
     NOT 
    [1]: 
     ['q', 'OR', 'r'] 

Die FollowedBy Begriffe, die InfixNotation fügt degenerierte Ebenen für Kollaps hinzu, indem sichergestellt wird, dass zwei oder mehr Begriffe gruppiert sind, bevor sie tatsächlich gruppiert werden. Sie verhindern auch die aufrufenden Analyseaktionen für Atome auf jeder Ebene der Operationsprioritätsdefinition.

Wenn Ihnen das egal ist, versuchen Sie es mit der abgespeckten Version.

(Bitte machen Sie auch ein wenig Zeit für Ihre Definition von UNICODE_CHARS - diese Zeichenfolge ist ein wenig zeitaufwändig zu generieren. Sie können diese Zeichenfolge in einem separaten Modul vorgenerieren und einfach importieren.)

+0

Vielen Dank für Ihre Beratung. Ich könnte es schneller machen 3/4. Aber ich muss es schneller 1/10 machen. Ich werde versuchen, Psyco oder etwas .. –

+0

Psyco ist nicht am Leben. Pypy ist auf Python 3.5 nicht verfügbar. –

+0

Ich verschiebe Grammer-Definitionen aus dem Funktionsumfang heraus. Die Leistung ist verbessert. Es ist 1/20. Vielen Dank! –

Verwandte Themen