Pyparsing - 令牌不可预测的顺序

时间:2010-01-25 18:01:25

标签: python pyparsing

我希望能够从一段文字中提取字母的类型和数量,其中字母可以是任何顺序。还有一些其他的解析正在进行中,但这一点让我难过!

input -> result
"abc" -> [['a',1], ['b',1],['c',1]]
"bbbc" -> [['b',3],['c',1]]
"cccaa" -> [['a',2],['c',3]]

我可以使用搜索或扫描并重复每个可能的字母,但是有一种干净的方式吗?

据我所知:

from pyparsing import *


def handleStuff(string, location, tokens):

        return [tokens[0][0], len(tokens[0])]


stype = Word("abc").setParseAction(handleStuff)
section =  ZeroOrMore(stype("stype"))


print section.parseString("abc").dump()
print section.parseString("aabcc").dump()
print section.parseString("bbaaa").dump()

5 个答案:

答案 0 :(得分:6)

一个解决方案:

text = 'sufja srfjhvlasfjkhv lasjfvhslfjkv hlskjfvh slfkjvhslk'
print([(x,text.count(x)) for x in set(text)])

没有涉及pyparsing,但似乎有点矫枉过正。

答案 1 :(得分:6)

我从描述中不清楚输入字符是否可以像“ababc”那样混合,因为在所有测试用例中,字母总是组合在一起。如果字母 始终组合在一起,则可以使用此pyparsing代码:

def makeExpr(ch):
    expr = Word(ch).setParseAction(lambda tokens: [ch,len(tokens[0])])
    return expr

expr = Each([Optional(makeExpr(ch)) for ch in "abc"])

for t in tests:
    print t,expr.parseString(t).asList()

每个构造负责按顺序进行匹配,而Word(ch)处理1到n的重复。解析操作负责将解析的标记转换为(字符,计数)元组。

答案 2 :(得分:3)

我喜欢Lennart's one-line solution

Alex mentions another great option如果您使用的是3.1

另一个选项是collections.defaultdict

>>> from collections import defaultdict
>>> mydict = defaultdict(int)
>>> for c in 'bbbc':
...   mydict[c] += 1
...
>>> mydict
defaultdict(<type 'int'>, {'c': 1, 'b': 3})

答案 3 :(得分:2)

如果你想要一种纯粹的pyparsing方法,这感觉很合适:

from pyparsing import *

# lambda to define expressions
def makeExpr(ch):
    expr = Literal(ch).setResultsName(ch, listAllMatches=True)
    return expr

expr = OneOrMore(MatchFirst(makeExpr(c) for c in "abc"))
expr.setParseAction(lambda tokens: [[a,len(b)] for a,b in tokens.items()])


tests = """\
abc
bbbc
cccaa
""".splitlines()

for t in tests:
    print t,expr.parseString(t).asList()

打印:

abc [['a', 1], ['c', 1], ['b', 1]]
bbbc [['c', 1], ['b', 3]]
cccaa [['a', 2], ['c', 3]]

但是这开始进入一个模糊的代码区域,因为它依赖于pyparsing的一些更神秘的功能。一般来说,我喜欢使用defaultdict的频率计数器(尚未尝试使用Counter),因为它非常清楚你正在做什么。

答案 4 :(得分:1)

分开 - 在Python 3.1中,collections.Counter使得这样的计数任务变得非常容易。可以找到适用于Python 2的Counter的良好版本here