2015-05-28 16 views
12

cách tốt nhất để xây dựng một từ điển từ một chuỗi như hình dưới đây là gì:Biến chuỗi với dấu ngoặc nhúng vào một cuốn từ điển

"{key1 value1} {key2 value2} {key3 {value with spaces}}" 

Vì vậy, chìa khóa luôn là một chuỗi không có dấu cách nhưng giá trị hoặc là một chuỗi hoặc một chuỗi trong dấu ngoặc nhọn (nó có dấu cách)?

Làm thế nào bạn sẽ dict nó vào:

{'key1': 'value1', 'key2': 'value2', 'key3': 'value with spaces'} 
+0

Làm thế nào để bạn xác định "cách tốt nhất"? Nhanh chóng, thanh lịch, có thể duy trì, ...? Ngoài ra, bạn đã thử gì? Điều gì làm việc và những gì không? Tại sao không? –

Trả lời

18
import re 
x="{key1 value1} {key2 value2} {key3 {value with spaces}}" 
print dict(re.findall(r"\{(\S+)\s+\{*(.*?)\}+",x)) 

Bạn có thể thử này.

Output:

{'key3': 'value with spaces', 'key2': 'value2', 'key1': 'value1'} 

đây với re.findall chúng tôi trích xuất keyvalue của nó. re.findall trả về một danh sách có bộ gồm tất cả các cặp khóa, giá trị.Sử dụng dict trong danh sách các bộ dữ liệu cung cấp câu trả lời cuối cùng. Read more here.

+2

Điều này thực sự tuyệt vời! Nó sẽ là một tuyệt vời nếu bạn có thể gửi một chút lời giải thích để tôi có thể tìm hiểu và hiểu điều này tốt hơn. Cảm ơn. –

+0

@vks Thật tuyệt vời! Tôi sẽ cập nhật nó như thế nào để hỗ trợ các trường hợp có khoảng trống xung quanh các dấu ngoặc như sau: "{key1 value1} {key2 value2} {key3 {value with spaces}}" – mtmt

+0

@mtmt 'print dict (re.findall (r" \ {\ s * (\ S +) \ s + \ {* (. *?) \} + ", X))' – vks

2

Giả sử bạn không có bất kỳ thứ gì trong chuỗi lồng nhiều hơn trong ví dụ của bạn, trước tiên bạn có thể sử dụng xác nhận lookahead/lookbehind để chia chuỗi thành cặp khóa-giá trị, tìm mẫu } { (phần cuối của một cặp dấu ngoặc và đầu của người khác.)

>>> str = '{key1 value1} {key2 value2} {key3 {value with spaces}}' 
>>> pairs = re.split('(?<=})\s*(?={)', str) 

này nói "trận đấu trên bất kỳ \s* (khoảng trắng) mà có một } trước khi nó và một { sau nó, nhưng không bao gồm những dấu ngoặc trong chính trận đấu. "

Sau đó, bạn có cặp khóa-giá trị của bạn:

>>> pairs 
['{key1 value1}', '{key2 value2}', '{key3 {value with spaces}}'] 

mà có thể được chia vào khoảng trắng với maxsplit tham số thiết lập để 1, để đảm bảo rằng nó chỉ chia trên không gian đầu tiên. Trong ví dụ này, tôi cũng đã sử dụng chỉ mục chuỗi ([1:-1]) để loại bỏ các dấu ngoặc nhọn mà tôi biết là ở đầu và cuối của mỗi cặp.

>>> simple = pairs[0] 
>>> complex = pairs[2] 
>>> simple 
'{key1 value1}' 
>>> complex 
'{key3 {value with spaces}}' 
>>> simple[1:-1] 
'key1 value1' 
>>> kv = re.split('\s+', simple[1:-1], maxsplit=1) 
>>> kv 
['key1', 'value1'] 
>>> kv3 = re.split('\s+', complex[1:-1], maxsplit=1) 
>>> kv3 
['key3', '{value with spaces}'] 

sau đó chỉ cần kiểm tra xem giá trị có được đặt trong dấu ngoặc nhọn và xóa chúng nếu bạn cần trước khi đưa chúng vào từ điển của bạn.

Nếu đảm bảo rằng các cặp khóa/giá trị sẽ luôn được phân tách bằng ký tự khoảng trắng, thì bạn có thể sử dụng chia chuỗi đồng bằng cũ thay thế.

>>> kv3 = complex[1:-1].split(' ', maxsplit=1) 
>>> kv3 
['key3', '{value with spaces}'] 
4

tôi không thể làm cho nó tao nhã hơn:

input = "{key1 value1} {key2 value2} {key3 {value with spaces}}" 
x = input.split("} {")    # creates list with keys and values 
y = [i.split(" {") for i in y]  # separates the list-values from keys 
# create final list with separated keys and values, removing brackets 
z = [[i.translate(None,"{").translate(None,"}").split() for i in j] for j in y] 

fin = {} 
for i in z: 
    fin[i[0][0]] = i[-1] 

Nó rất rất hacky, nhưng nó phải thực hiện công việc.

+0

Nghĩ rằng giá trị thứ ba là danh sách các giá trị. câu trả lời của vks là tốt hơn nhiều. – Renatius

+2

Điều này có thể bị hack nhưng có vẻ như tránh regex quá mức, điều này có thể có lợi trong một số trường hợp. – Pureferret

1

Câu trả lời của @vks không kiểm tra các dấu ngoặc ôm cân bằng.Hãy thử như sau:

>>> x="{key3 {value with spaces} {key4 value4}}" 
>>> dict(re.findall(r"\{(\S+)\s+\{*(.*?)\}+",x)) 
{'key3': 'value with spaces', 'key4': 'value4'} 

thử thay vì:

>>> dict(map(lambda x:[x[0],x[2]], re.findall(r'\{(\S+)\s+(?P<Brace>\{)?((?(Brace)[^{}]*|[^{}\s]*))(?(Brace)\})\}',x))) 
{'key4': 'value4'} 

có nghĩa là, nó phù hợp với chỉ trên một phần có thanh giằng đúng.

lưu kết quả phù hợp của { và sau đó (?(Brace)\}) chỉ khớp với } chỉ khi kết hợp đầu tiên và dấu ngoặc ôm phải khớp với cặp. Và theo cấu trúc (?(Brace)...|...), nếu \Brace khớp nhau, phần giá trị có thể chứa bất kỳ thứ gì ngoại trừ niềng răng ([^{}]*), nếu không thì không được phép ([^{}\s]*).

Khi dấu ngoặc kép tùy chọn được khớp trong regexp và do đó được trả về trong danh sách, chúng ta cần trích xuất phần tử 0 và 2 từ mỗi danh sách theo hàm map().

Regexps dễ bị lộn xộn.

Các vấn đề liên quan