Search code examples
pythonpyparsing

How capture everything before operator in Pyparsing


Referring to Pyparsing problem with operators

I am trying to create pyparsing grammar. I want to capture space separated entity as single word before operator "and"/"or".

Expected result is :

(United kingdom or Sweden)
['United kingdom','or','Sweden']

What i am getting is

['United', 'kingdom','or','Sweden']

Code so far

from pyparsing import *
import json

QUOTED = quotedString.setParseAction(removeQuotes)
OAND = CaselessLiteral("and")
OOR = CaselessLiteral("or")
ONOT = CaselessLiteral("not")
WORDWITHSPACE = Combine(OneOrMore(Word(printables.replace("(", "").replace(")", "")) | White(
    ' ') + ~(White() | OAND | ONOT | OOR)))
TERM = (QUOTED | WORDWITHSPACE)
EXPRESSION = operatorPrecedence(TERM,
                                [
                                    (ONOT, 1, opAssoc.RIGHT),
                                    (OAND, 2, opAssoc.LEFT),
                                    (OOR, 2, opAssoc.LEFT)
                                ])

STRING = OneOrMore(EXPRESSION) + StringEnd()

Solution

  • I redefinend WORDWITHSPACE as follows:

    # space-separated words are easiest to define using just OneOrMore
    # must use a negative lookahead for and/not/or operators, and this must come
    # at the beginning of the expression
    WORDWITHSPACE = OneOrMore(~(OAND | ONOT | OOR) + Word(printables, excludeChars="()"))
    
    # use a parse action to recombine words into a single string
    WORDWITHSPACE.addParseAction(' '.join)
    

    With these changes to your code sample, I was able to write:

    tests = """
        # basic test
        United Kingdom or Sweden
    
        # multiple operators at the same precedence level
        United Kingdom or Sweden or France
    
        # implicit grouping by precedence - 'and' is higher prec than 'or
        United Kingdom or Sweden and People's Republic of China
    
        # use ()'s to override precedence of 'and' over 'or
        (United Kingdom or Sweden) and People's Republic of China
        """
    
    EXPRESSION.runTests(tests, fullDump=False)
    

    and get

    # basic test
    United Kingdom or Sweden
    [['United Kingdom', 'or', 'Sweden']]
    
    # multiple operators at the same precedence level
    United Kingdom or Sweden or France
    [['United Kingdom', 'or', 'Sweden', 'or', 'France']]
    
    # implicit grouping by precedence - 'and' is higher prec than 'or
    United Kingdom or Sweden and People's Republic of China
    [['United Kingdom', 'or', ['Sweden', 'and', "People's Republic of China"]]]
    
    # use ()'s to override precedence of 'and' over 'or
    (United Kingdom or Sweden) and People's Republic of China
    [[['United Kingdom', 'or', 'Sweden'], 'and', "People's Republic of China"]]