2012-04-03 13 views
10

Estoy tratando de analizar cadenas de la forma:no puede conseguir pyparsing Dict() para devolver el diccionario anidada

'foo(bar:baz;x:y)' 

me gustaría que los resultados se devuelven en forma de un diccionario anidada, es decir, para la cadena anterior, los resultados deberían tener este aspecto:

{ 'foo' : { 'bar' : 'baz', 'x' : 'y' } } 

pesar de las numerosas combinaciones de Dict() y Grupo() no puedo conseguir que funcione. Mi (una de las versiones de) la gramática se parece a esto:

import pyparsing as pp 
field_name = pp.Word(pp.alphanums) 
field_value = pp.Word(pp.alphanums) 
colon = pp.Suppress(pp.Literal(':')) 

expr = pp.Dict( 
    pp.Group( 
     field_name + \ 
     pp.nestedExpr( 
      content = pp.delimitedList( 
       pp.Group(field_name + colon + field_value), 
       delim = ';' 
      ) 
     ) 
    ) 
) 

y ahora, los resultados son los siguientes:

In [62]: str = 'foo(bar:baz;x:y)' 

In [63]: expr.parseString(str).asList() 
Out[63]: [['foo', [['bar', 'baz'], ['x', 'y']]]] 

In [64]: expr.parseString(str).asDict() 
Out[64]: {'foo': ([(['bar', 'baz'], {}), (['x', 'y'], {})], {})} 

In [65]: print(expr.parseString(str).dump()) 
Out[65]: [['foo', [['bar', 'baz'], ['x', 'y']]]] 
     - foo: [['bar', 'baz'], ['x', 'y']] 

Así que la versión asList() se ve bastante bien para mí y debe producir un diccionario Estoy después de lo que pienso. Por supuesto, dado que (de la forma en que lo entiendo, corrígeme) Dict() analizará las listas de tokens utilizando el primer elemento de la lista como clave y todo el resto como valores de esa clave en un diccionario. Esto funciona en la medida en que el diccionario no está anidado. Por ejemplo, en este caso:

expr = pp.Dict( 
    pp.delimitedList( 
     pp.Group(field_name + colon + field_value), 
     delim = ';' 
    ) 
) 

In [76]: expr.parseString('foo:bar;baz:x').asDict() 
Out[76]: {'baz': 'x', 'foo': 'bar'} 

Por lo tanto, la cuestión es lo que falla en el primer caso (y mi comprensión del problema) o tal vez Dict() no puede hacer frente a este caso? Podría usar asList() y convertir eso manualmente en un diccionario, pero preferiría tener pyparsing hacerlo :)

Cualquier ayuda o indicaciones serían muy apreciadas.

Gracias.

Respuesta

6

dos problemas:

  • Usted se echa en falta un pp.Dict alrededor pp.delimitedList hacer asDict en el trabajo resultado interno correctamente
  • Sólo está llamando asDict en el exterior ParsingResult ejemplo, dejando el interior ParsingResult "no interpretado"

he intentado lo siguiente:

from pyparsing import * 
field_name = field_val = Word(alphanums) 
colon = Suppress(Literal(':')) 

expr = Dict(Group(
    field_name + 
    nestedExpr(content = 
     Dict(delimitedList( 
      Group(field_name + colon + field_value), 
      delim = ';' 
     )) 
    ) 
)) 

luego se usa de esta manera:

>>> res = expr.parseString('foo(bar:baz;x:y)') 
>>> type(res['foo']) 
<class 'pyparsing.ParseResults'> 
>>> { k:v.asDict() for k,v in res.asDict().items() } 
{'foo': {'x': 'y', 'bar': 'baz'}} 
+0

Buena atrapada en la falta 'pp.Dict'. Además, intente imprimir 'res.dump()' para ver las claves y valores anidados. (Dado que 'res' es un objeto ParseResults, admitirá el acceso al estilo dict anidado sin convertir usando asDict:' res ['foo'] ['x'] 'da 'y'; o puede usar la notación de atributo con puntos como siempre que las claves sean bonitas identificadores de Python: 'res.foo.bar' da 'baz'.) – PaulMcG

+0

Hola, @Paul, es agradable recibir un cumplido del propio autor :) Encuentro' res.dump() 'no mucho más informativo que simplemente 'str (res)', pero tal vez simplemente no sé cómo interpretarlo? Nunca he usado pyparsing antes, debería decir. –

+0

¡Muchas gracias, Niklas! No sabía que dentro de los resultados también hay instancias de ParseResults, pensé que ya serían listas o dicts. Paul: gracias por la sugerencia de usar como dict sin conversión, ¡esto podría ser útil en lo que estoy trabajando! :) – kgr

Cuestiones relacionadas