2012-04-03 17 views
10

Tôi đang cố gắng để phân tích chuỗi có dạng:Không thể có được pyparsing Dict() để trở về từ điển lồng nhau

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

Tôi muốn kết quả được trả về dưới hình thức một cuốn từ điển lồng nhau, tức là cho chuỗi trên, kết quả sẽ giống như thế này:

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

dù có rất nhiều sự kết hợp của Dict() và Group() tôi không thể có được nó để làm việc. My (một trong những phiên bản của) ngữ pháp trông như thế này:

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 = ';' 
      ) 
     ) 
    ) 
) 

và bây giờ, kết quả như sau:

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

Vì vậy, các phiên bản asList() trông khá tốt với tôi và cần tạo ra một từ điển Tôi sau khi tôi nghĩ. Dict() sẽ phân tích danh sách các mã thông báo bằng cách sử dụng phần tử đầu tiên của danh sách dưới dạng khóa và tất cả phần còn lại làm giá trị của khóa đó trong từ điển. Điều này làm việc trong từ điển không phải là lồng nhau. Ví dụ: trong trường hợp này:

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'} 

Vì vậy, câu hỏi là sai với trường hợp đầu tiên (và sự hiểu biết của tôi về vấn đề) hoặc có lẽ Dict() không thể đối phó với trường hợp như vậy? Tôi có thể sử dụng asList() và chuyển đổi thủ công thành từ điển, nhưng tôi muốn có pyparsing làm điều đó :)

Bất kỳ trợ giúp hoặc chỉ đường nào sẽ được đánh giá cao.

Cảm ơn bạn.

Trả lời

6

Hai vấn đề:

  • Bạn đang thiếu một pp.Dict xung quanh pp.delimitedList để làm asDict về công tác kết quả bên trong một cách chính xác
  • Bạn chỉ được gọi asDict trên ngoài cùng ParsingResult dụ, để lại bên trong ParsingResult "uninterpreted"

Tôi đã thử cách sau:

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 = ';' 
     )) 
    ) 
)) 

Sau đó, sử dụng nó như thế này:

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

đẹp bắt trên mất tích 'pp.Dict'. Ngoài ra, hãy thử in 'res.dump()' để xem các giá trị và khóa lồng nhau. (Vì 'res' là đối tượng ParseResults, nó sẽ hỗ trợ truy cập kiểu dict lồng nhau mà không chuyển đổi bằng cách sử dụng asDict:' res ['foo'] ['x'] 'cho 'y'; hoặc bạn có thể sử dụng ký hiệu thuộc tính chấm như miễn là các khóa là các mã nhận dạng Python tốt đẹp: 'res.foo.bar' cho 'baz'.) – PaulMcG

+0

Xin chào @Paul, nhận được lời khen từ chính tác giả :) Tôi tìm thấy' res.dump() 'không nhiều thông tin hơn hơn là 'str (res)', nhưng có lẽ tôi chỉ không biết cách diễn giải nó? Chưa bao giờ sử dụng pyparsing trước đây, tôi nên nói. –

+0

Cảm ơn bạn rất nhiều Niklas! Tôi đã không nhận thức được rằng bên trong các kết quả cũng có trường hợp ParseResults, tôi nghĩ rằng họ sẽ là một trong hai danh sách hoặc dicts đã. Paul - cảm ơn cho mẹo sử dụng như dict mà không cần chuyển đổi, điều này thực sự có thể có ích trong những gì tôi đang làm việc! :) – kgr