2010-01-25 8 views
7

Tôi muốn có thể lấy loại và số lượng chữ cái từ một đoạn văn bản trong đó các chữ cái có thể theo thứ tự bất kỳ. Có một số phân tích cú pháp khác đang diễn ra mà tôi đã làm việc, nhưng bit này đã khiến tôi bối rối!Pyparsing - nơi đặt mã thông báo không thể đoán trước

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

Tôi có thể sử dụng tìm kiếm hoặc quét và lặp lại cho từng chữ cái có thể, nhưng có cách nào để làm việc đó không?

Đây là như xa như tôi nhận:

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() 

Trả lời

6

Tôi không rõ ràng từ mô tả của bạn cho dù các ký tự đầu vào có thể được trộn lẫn như "ababc", vì trong tất cả các trường hợp thử nghiệm của bạn, các chữ cái luôn được nhóm lại với nhau. Nếu các chữ cái được luôn nhóm lại với nhau, bạn có thể sử dụng mã pyparsing này:

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() 

Các Mỗi cấu trúc chăm sóc phù hợp trong trật tự, và Word (ch) xử lý 1-to-n lặp lại. Hành động phân tích cú pháp sẽ chăm sóc chuyển đổi các mã thông báo được phân tách thành các ký tự (ký tự, số lượng).

+0

Có các ký tự được nhóm lại để điều này hoàn hảo. Cảm ơn các giải pháp và giải thích. Loving pyparsing! – PhoebeB

6

Một giải pháp:

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

Không pyparsing tham gia, nhưng nó có vẻ như quá mức cần thiết.

+0

Tôi nghĩ rằng tôi sẽ đi với điều này bằng cách sử dụng pyparsing để kéo chunk và setParseAction để xử lý nó với điều này. Vẫn được quan tâm để biết nếu có một giải pháp pyparsing mặc dù! – PhoebeB

+0

Cảm ơn giải pháp của bạn - bây giờ nó đã bị pp bởi một giải pháp, nhưng cảm ơn sự giúp đỡ của bạn và giải pháp rất gọn gàng! – PhoebeB

1

cách nhau bằng pyparsing - bằng Python 3.1, collections.Counter làm nhiệm vụ đếm thực sự dễ dàng. Bạn có thể tìm thấy phiên bản tốt của Counter cho Python 2 here.

+0

Giống như lớp Counter - sẽ ghi nhớ điều đó cho những thứ khác. Cảm ơn. – PhoebeB

2

Nếu bạn muốn có một cách tiếp cận thuần pyparsing, điều này cảm thấy về quyền:

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() 

Prints :

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

Nhưng điều này bắt đầu nhận được vào một khu vực mã mờ, vì nó dựa trên một số tính năng phức tạp hơn của pyparsing. Nói chung, tôi thích các bộ đếm tần số sử dụng defaultdict (chưa thử Counter), vì nó khá rõ ràng chỉ là những gì bạn đang làm.