PyParsing: 不允许将所有标记传递给 setParseAction()

我正在解析"CS 2110 或 INFO 3300"之类的句子。我想输出以下格式:
[[(“CS” 2110)], [(“INFO”, 3300)]]
为此,我认为可以使用 setParseAction()。但是,statementParse() 中的 print 语句表明实际上只传递给最后一个标记:

>>> statement.parseString("CS 2110 or INFO 3300")
Match [{Suppress:("or") Re:('[A-Z]{2,}') Re:('[0-9]{4}')}] at loc 7(1,8)
string CS 2110 or INFO 3300
loc: 7 
tokens: ['INFO', 3300]
Matched [{Suppress:("or") Re:('[A-Z]{2,}') Re:('[0-9]{4}')}] -> ['INFO', 3300]
(['CS', 2110, 'INFO', 3300], {'Course': [(2110, 1), (3300, 3)], 'DeptCode': [('CS', 0), ('INFO', 2)]})

我希望所有标记都通过,但它只是 [‘INFO’, 3300]。我做错了什么?还是有其他方法可以生成所需的结果?
这是 pyparsing 代码:

from pyparsing import *

def statementParse(str, location, tokens):
    print "string %s" % str
    print "loc: %s " % location
    print "tokens: %s" % tokens

DEPT_CODE = Regex(r'[A-Z]{2,}').setResultsName("DeptCode")
COURSE_NUMBER = Regex(r'[0-9]{4}').setResultsName("CourseNumber")

OR_CONJ = Suppress("or")

COURSE_NUMBER.setParseAction(lambda s, l, toks : int(toks[0]))

course = DEPT_CODE + COURSE_NUMBER.setResultsName("Course")

statement = course + Optional(OR_CONJ + course).setParseAction(statementParse).setDebug()

2、解决方案

答案 1:

>>> statement = (course + Optional(OR_CONJ + course)).setParseAction(statementParse).setDebug()
>>> statement.parseString("CS 2110 or INFO 3300")    

会给出

Match {Re:('[A-Z]{2,}') Re:('[0-9]{4}') [{Suppress:("or") Re:('[A-Z]{2,}') Re:('[0-9]{4}')}]} at loc 0(1,1)
string CS 2110 or INFO 3300
loc: 0 
tokens: ['CS', 2110, 'INFO', 3300]
Matched {Re:('[A-Z]{2,}') Re:('[0-9]{4}') [{Suppress:("or") Re:('[A-Z]{2,}') Re:('[0-9]{4}')}]} -> ['CS', 2110, 'INFO', 3300]
(['CS', 2110, 'INFO', 3300], {'Course': [(2110, 1), (3300, 3)], 'DeptCode': [('CS', 0), ('INFO', 2)]})

不过我怀疑你真正想要的是对每个 course 设置解析操作,而不是对 statement 设置:

>>> statement = course + Optional(OR_CONJ + course)
>>> statement.parseString("CS 2110 or INFO 3300")                               

会给出

Match {Re:('[A-Z]{2,}') Re:('[0-9]{4}')} at loc 0(1,1)
string CS 2110 or INFO 3300
loc: 0 
tokens: ['CS', 2110]
Matched {Re:('[A-Z]{2,}') Re:('[0-9]{4}')} -> ['CS', 2110]
Match {Re:('[A-Z]{2,}') Re:('[0-9]{4}')} at loc 10(1,11)
string CS 2110 or INFO 3300
loc: 10 
tokens: ['INFO', 3300]
Matched {Re:('[A-Z]{2,}') Re:('[0-9]{4}')} -> ['INFO', 3300]
(['CS', 2110, 'INFO', 3300], {'Course': [(2110, 1), (3300, 3)], 'DeptCode': [('CS', 0), ('INFO', 2)]})

答案 2:
为了保留 “CS 2110” 和 “INFO 3300” 中的标记位,我建议你在 course 的定义中包裹一个 Group:

course = Group(DEPT_CODE + COURSE_NUMBER).setResultsName("Course")

它看起来你还想直接解析出某种搜索表达式,如 “x 与 y 或 z”。这个问题具有一些细微之处,我建议你查看 pyparsing wiki 上的一些示例,了解如何构建此类表达式。否则,你最终会得到由 Optional(“or” + this) 和 ZeroOrMore(“and” + that) 片段组成的混乱情况。作为最后的手段,你甚至可以使用具有 operatorPrecedence 的东西,例如:

DEPT_CODE = Regex(r'[A-Z]{2,}').setResultsName("DeptCode")        
COURSE_NUMBER = Regex(r'[0-9]{4}').setResultsName("CourseNumber")
course = Group(DEPT_CODE + COURSE_NUMBER)

courseSearch = operatorPrecedence(course, 
    [
    ("not", 1, opAssoc.RIGHT),
    ("and", 2, opAssoc.LEFT),
    ("or", 2, opAssoc.LEFT),
    ])

(你可能需要从 SourceForge SVN 下载最新的 1.5.3 版本才能运行此代码。)

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值