【问题标题】:pyparsing to parse a string made of booleanpyparsing 解析一个由布尔值组成的字符串
【发布时间】:2014-05-28 03:08:55
【问题描述】:

我想使用非常好的包pyparsing来解析以下类型的字符串。

atomname * 和 atomindex 1,2,3

atomname xxx,yyy 或 atomtype rrr,sss

硫醇

不是原子索引 1,2,3

不是 (atomindex 4,5,6) 或 atomname *

基于此解析,我会将匹配项链接到将执行的特定函数调用 原子的选择。

所有选择关键字(atomname,atomindex,thiol ...)都存储在一个列表中(即selkwds)。

我试过了,但失败了:

keyword = oneOf(selkwds,caseless=True).setParseAction(self.__parse_keyword)

func_call = Forward()

func_call << (keyword + commaSeparatedList).setParseAction(self.__parse_expression)

func_call = operatorPrecedence(func_call, [(NOT, 1, opAssoc.RIGHT, self.__not),
                                           (AND, 2, opAssoc.LEFT , self.__and),
                                           (OR , 2, opAssoc.LEFT , self.__or)])

其中self._and, self._or, self._not, self._parse_keyword, self._parse_expression 是为转换后的字符串的未来eval 修改令牌的方法。

你知道如何解决这个问题吗?

非常感谢

埃里克

【问题讨论】:

    标签: python pyparsing


    【解决方案1】:

    在此修改后的解析器版本中查看嵌入的 cmets:

    from pyparsing import *
    
    selkwds = "atomname atomindex atomtype thiol".split()
    func_name = MatchFirst(map(CaselessKeyword, selkwds))
    NOT,AND,OR = map(CaselessKeyword,"NOT AND OR".split())
    keyword = func_name | NOT | AND | OR
    
    func_call = Forward()
    
    integer = Word(nums).setParseAction(lambda t: int(t[0]))
    alphaword = Word(alphas,alphanums)
    
    # you have to be specific about what kind of things can be an arg,
    # otherwise, an argless function call might process the next
    # keyword or boolean operator as an argument;
    # this kind of lookahead is commonly overlooked by those who
    # assume that the parser will try to do some kind of right-to-left
    # backtracking in order to implicitly find a token that could be
    # mistaken for the current repetition type; pyparsing is purely
    # left-to-right, and only does lookahead if you explicitly tell it to
    # I assume that a func_call could be a function argument, otherwise
    # there is no point in defining it as a Forward
    func_arg = ~keyword + (integer | func_call | alphaword)
    
    # add Groups to give structure to your parsed data - otherwise everything
    # just runs together - now every function call parses as exactly two elements:
    # the keyword and a list of arguments (which may be an empty list, but will
    # still be a list)
    func_call << Group(func_name + Group(Optional(delimitedList(func_arg) | '*')))
    
    # don't name this func_call, its confusing with what you've 
    # already defined above
    func_call_expr = operatorPrecedence(func_call, [(NOT, 1, opAssoc.RIGHT),
                                               (AND, 2, opAssoc.LEFT),
                                               (OR , 2, opAssoc.LEFT)])
    

    让我们测试一下:

    tests = """\
        atomname * and atomindex 1,2,3
        atomname xxx,yyy or atomtype rrr,sss
        thiol
        not atomindex 1,2,3
        not (atomindex 4,5,6) or atomname *""".splitlines()
    
    for test in tests:
        print test.strip()
        print func_call_expr.parseString(test).asList()
        print
    

    打印:

    atomname * and atomindex 1,2,3
    [[['atomname', ['*']], 'AND', ['atomindex', [1, 2, 3]]]]
    
    atomname xxx,yyy or atomtype rrr,sss
    [[['atomname', ['xxx', 'yyy']], 'OR', ['atomtype', ['rrr', 'sss']]]]
    
    thiol
    [['thiol', []]]
    
    not atomindex 1,2,3
    [['NOT', ['atomindex', [1, 2, 3]]]]
    
    not (atomindex 4,5,6) or atomname *
    [[['NOT', ['atomindex', [4, 5, 6]]], 'OR', ['atomname', ['*']]]]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-07-10
      • 1970-01-01
      • 1970-01-01
      • 2013-08-22
      • 2011-06-14
      • 2019-02-10
      • 1970-01-01
      相关资源
      最近更新 更多