2010-01-25 11 views
7

Quiero ser capaz de sacar el tipo y el recuento de letras de un texto donde las letras podrían estar en cualquier orden. Hay algún otro análisis que estoy trabajando, pero este bit me ha dejado perplejo.Pyparsing - donde el orden de los tokens en impredecibles

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

Podría buscar o escanear y repetir para cada posible letra, pero ¿hay una forma clara de hacerlo?

Esto es por lo que yo tengo:

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

Respuesta

6

No estaba claro por su descripción si los caracteres de entrada podrían mezclarse como "ababc", ya que en todos los casos de prueba, las letras siempre se agruparon juntas. Si las letras están siempre agrupados, se puede utilizar este código 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() 

La Cada construcción se encarga de hacer coincidir fuera de orden, y Word (ch) maneja la repetición-1 a n. La acción de análisis se ocupa de convertir los tokens analizados en las tuplas (de caracteres).

+0

Sí, los caracteres están agrupados por lo que es perfecto. Gracias por la solución y la explicación. ¡Amando pyparsing! – PhoebeB

6

Una solución:

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

Sin pyparsing involucrado, pero parece un exceso.

+0

Creo que voy a ir con esto usando pyparsing para extraer el fragmento y configurar ParseAction para procesarlo con esto. ¡Sin embargo, todavía estará interesado en saber si hay una solución de pyparsing! – PhoebeB

+0

Gracias por su solución, ahora ha sido superada por la pyper, pero gracias por su ayuda y la solución muy ordenada! – PhoebeB

1

pyparsing aparte - en Python 3.1, collections.Counter hace que estas tareas de recuento sean realmente fáciles. Una buena versión de Counter para Python 2 se puede encontrar en here.

+0

Al igual que la clase Counter: lo tendremos en cuenta para otras cosas. Gracias. – PhoebeB

2

Si desea un enfoque puro pyparsing, esto se siente sobre la derecha:

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]] 

Pero esto comienza a entrar en un área de código oscuro, ya que se basa en algunas de las características más arcanas de pyparsing. En general, me gustan los contadores de frecuencia que usan el valor predeterminado (no he probado el contador aún), ya que es bastante claro lo que estás haciendo.

Cuestiones relacionadas