【问题标题】:PyParsing: Is this correct use of setParseAction()?PyParsing:这是正确使用 setParseAction() 吗?
【发布时间】:2011-02-25 19:54:16
【问题描述】:

我有这样的字符串:

"MSE 2110, 3030, 4102"

我想输出:

[("MSE", 2110), ("MSE", 3030), ("MSE", 4102)]

这是我的做法,虽然我还没有完全明白:

def makeCourseList(str, location, tokens):
    print "before: %s" % tokens

    for index, course_number in enumerate(tokens[1:]):
        tokens[index + 1] = (tokens[0][0], course_number)

    print "after: %s" % tokens

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

course_data = (course + ZeroOrMore(Suppress(',') + COURSE_NUMBER)).setParseAction(makeCourseList)

这个输出:

>>> course.parseString("CS 2110")
([(['CS', 2110], {})], {})
>>> course_data.parseString("CS 2110, 4301, 2123, 1110")
before: [['CS', 2110], 4301, 2123, 1110]
after: [['CS', 2110], ('CS', 4301), ('CS', 2123), ('CS', 1110)]
([(['CS', 2110], {}), ('CS', 4301), ('CS', 2123), ('CS', 1110)], {})

这是正确的做法吗,还是我完全不行了?

此外, 的输出也不完全正确 - 我希望 course_data 发出一个格式相同的 course 符号列表。现在,第一门课程与其他课程不同。 (它有一个{},而其他没有。)

【问题讨论】:

  • 我认为你应该接受答案。

标签: python parsing nlp pyparsing


【解决方案1】:

此解决方案在解析时记住部门,并在找到数字时发出 (dept,coursenum) 元组。

from pyparsing import Suppress,Word,ZeroOrMore,alphas,nums,delimitedList

data = '''\
MSE 2110, 3030, 4102
CSE 1000, 2000, 3000
'''

def memorize(t):
    memorize.dept = t[0]

def token(t):
    return (memorize.dept,int(t[0]))

course = Suppress(Word(alphas).setParseAction(memorize))
number = Word(nums).setParseAction(token)
line = course + delimitedList(number)
lines = ZeroOrMore(line)

print lines.parseString(data)

输出:

[('MSE', 2110), ('MSE', 3030), ('MSE', 4102), ('CSE', 1000), ('CSE', 2000), ('CSE', 3000)]

【讨论】:

    【解决方案2】:

    这是正确的做法吗? 我完全关闭了?

    这是一种方法,当然还有其他方法(例如,将两个绑定方法用作解析操作 - 因此方法所属的实例可以保持状态 - 一个用于部门代码,另一个用于课程编号)。

    parseString 调用的返回值更难遵从你的意愿(尽管我确信足够的黑魔法会做到这一点,我期待 Paul McGuire 解释如何;-),所以为什么不去约束-方法路线如...:

    from pyparsing import *
    
    DEPT_CODE = Regex(r'[A-Z]{2,}').setResultsName("DeptCode")
    COURSE_NUMBER = Regex(r'[0-9]{4}').setResultsName("CourseNumber")
    
    class MyParse(object):
      def __init__(self):
          self.result = None
    
      def makeCourseList(self, str, location, tokens):
          print "before: %s" % tokens
    
          dept = tokens[0][0]
          newtokens = [(dept, tokens[0][1])]
          newtokens.extend((dept, tok) for tok in tokens[1:])
    
          print "after: %s" % newtokens
          self.result = newtokens
    
    course = Group(DEPT_CODE + COURSE_NUMBER).setResultsName("Course")
    
    inst = MyParse()
    course_data = (course + ZeroOrMore(Suppress(',') + COURSE_NUMBER)
        ).setParseAction(inst.makeCourseList)
    ignore = course_data.parseString("CS 2110, 4301, 2123, 1110")
    print inst.result
    

    这会发出:

    before: [['CS', '2110'], '4301', '2123', '1110']
    after: [('CS', '2110'), ('CS', '4301'), ('CS', '2123'), ('CS', '1110')]
    [('CS', '2110'), ('CS', '4301'), ('CS', '2123'), ('CS', '1110')]
    

    如果我正确阅读了您的规格,这似乎是您所需要的。

    【讨论】:

      【解决方案3】:
      data = '''\
      MSE 2110, 3030, 4102
      CSE 1000, 2000, 3000'''
      
      def get_courses(data):
          for row in data.splitlines():
              department, *numbers = row.replace(",", "").split()
              for number in numbers:
                  yield department, number
      

      这将为课程代码提供一个生成器。如果需要,可以使用list() 制作列表,也可以直接对其进行迭代。

      【讨论】:

        【解决方案4】:

        当然,每个人都喜欢PyParsing。对于像这种拆分这样简单的东西来说,理解起来要容易得多:

        data = '''\
        MSE 2110, 3030, 4102
        CSE 1000, 2000, 3000'''
        
        all = []
        for row in data.split('\n'):
                klass,num_l = row.split(' ',1)
                all.extend((klass,int(num)) for num in num_l.split(','))
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-09-12
          • 1970-01-01
          • 2015-03-09
          • 2018-08-13
          • 2015-12-19
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多