我希望能够从一段文字中提取字母的类型和数量,其中字母可以是任何顺序。还有一些其他的解析正在进行中,但这一点让我难过!
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()
答案 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。