Tách một chuỗi được phân tách bằng dấu chấm phẩy thành một từ điển, bằng Python


84

Tôi có một chuỗi trông như thế này:

"Name1=Value1;Name2=Value2;Name3=Value3"

Có một lớp / hàm tích hợp sẵn trong Python sẽ lấy chuỗi đó và tạo từ điển, như thể tôi đã làm điều này:

dict = {
    "Name1": "Value1",
    "Name2": "Value2",
    "Name3": "Value3"
}

Tôi đã xem qua các mô-đun có sẵn nhưng dường như không thể tìm thấy bất kỳ thứ gì phù hợp.


Cảm ơn, tôi biết cách tự tạo mã có liên quan, nhưng vì các giải pháp nhỏ như vậy thường là các trường của tôi đang chờ xảy ra (tức là ai đó viết: Name1 = 'Value1 = 2';), v.v. nên tôi thường thích một số trước chức năng đã kiểm tra.

Sau đó tôi sẽ tự làm.


Câu hỏi của bạn có yêu cầu hỗ trợ s = r'Name1='Value=2';Name2=Value2;Name3=Value3;Name4="Va\"lue;\n3"'đầu vào không (lưu ý: dấu chấm phẩy bên trong chuỗi được trích dẫn, \ndấu ngoặc kép được sử dụng dấu gạch chéo ngược, dấu ngoặc kép được sử dụng, cả dấu nháy đơn và dấu ngoặc kép đều được sử dụng)?
jfs

Câu hỏi này của tôi đã hơn 6 năm tuổi, mã liên quan đến điều này đã được thay thế từ lâu :) Và không, nó không yêu cầu hỗ trợ báo giá. Tôi chỉ muốn có một hàm dựng sẵn thay vì tự viết một cái gì đó. Tuy nhiên, mã đã mất từ ​​lâu.
Lasse V. Karlsen

Câu trả lời:


144

Không có nội dung, nhưng bạn có thể thực hiện điều này khá đơn giản với sự hiểu biết của trình tạo:

s= "Name1=Value1;Name2=Value2;Name3=Value3"
dict(item.split("=") for item in s.split(";"))

[Chỉnh sửa] Từ bản cập nhật của bạn, bạn cho biết bạn có thể cần xử lý phần trích dẫn. Điều này làm phức tạp mọi thứ, tùy thuộc vào định dạng chính xác bạn đang tìm kiếm là gì (những ký tự trích dẫn nào được chấp nhận, ký tự thoát nào, v.v.). Bạn có thể muốn xem mô-đun csv để xem nó có thể che được định dạng của bạn hay không. Đây là một ví dụ: (Lưu ý rằng API hơi khó hiểu đối với ví dụ này, vì CSV được thiết kế để lặp lại qua một chuỗi các bản ghi, do đó, các lệnh gọi .next () mà tôi đang thực hiện chỉ cần xem dòng đầu tiên. Điều chỉnh để phù hợp với nhu cầu của bạn):

>>> s = "Name1='Value=2';Name2=Value2;Name3=Value3"

>>> dict(csv.reader([item], delimiter='=', quotechar="'").next() 
         for item in csv.reader([s], delimiter=';', quotechar="'").next())

{'Name2': 'Value2', 'Name3': 'Value3', 'Name1': 'Value1=2'}

Tuy nhiên, tùy thuộc vào cấu trúc chính xác của định dạng, bạn có thể cần viết trình phân tích cú pháp đơn giản của riêng mình.


mã không xử lý trích dẫn, hãy thử: s = "Name1='Value;2';Name2=Value2;Name3=Value3"(lưu ý: dấu chấm phẩy trong Name1giá trị được trích dẫn ).
jfs

1
Tôi không biết tại sao ví dụ thứ hai ném AttributeError: '_csv.reader' object has no attribute 'next'cho tôi. Tất nhiên là tôi đã làm import csv.
Youngjae

@Brian Có cách nào để lưu trữ các giá trị dưới dạng số nguyên thay vì chuỗi không?
ChasedByDeath

6

Điều này gần đạt được những gì bạn muốn:

>>> import urlparse
>>> urlparse.parse_qs("Name1=Value1;Name2=Value2;Name3=Value3")
{'Name2': ['Value2'], 'Name3': ['Value3'], 'Name1': ['Value1']}

2
nó bị hỏng nếu có &hoặc %trong đầu vào.
jfs

@jfs nhưng chuỗi không chứa một trong hai.
Vishal Singh

@VishalSingh: hầu hết khách truy cập trên StackOverflow đến từ google và do đó câu trả lời ở đây không chỉ dành cho người đăng ban đầu đã đặt câu hỏi. Nếu tôi đến đây để tìm cách phân tích cú pháp "chuỗi được phân tách bằng dấu chấm phẩy sang từ điển, bằng Python" thì các chuỗi của tôi có thể chứa &hoặc %- ít nhất, điều đáng nói là câu trả lời không hoạt động cho các chuỗi như vậy.
jfs

3
s1 = "Name1=Value1;Name2=Value2;Name3=Value3"

dict(map(lambda x: x.split('='), s1.split(';')))

1

Nó có thể được thực hiện đơn giản bằng cách nối chuỗi và hiểu danh sách

",".join(["%s=%s" % x for x in d.items()])

>>d = {'a':1, 'b':2}
>>','.join(['%s=%s'%x for x in d.items()])
>>'a=1,b=2'

-2
easytiger $ cat test.out test.py | sed 's/^/    /'
p_easytiger_quoting:1.84563302994
{'Name2': 'Value2', 'Name3': 'Value3', 'Name1': 'Value1'}
p_brian:2.30507516861
{'Name2': 'Value2', 'Name3': "'Value3'", 'Name1': 'Value1'}
p_kyle:7.22536420822
{'Name2': ['Value2'], 'Name3': ["'Value3'"], 'Name1': ['Value1']}
import timeit
import urlparse

s = "Name1=Value1;Name2=Value2;Name3='Value3'"

def p_easytiger_quoting(s):
    d = {}
    s = s.replace("'", "")
    for x in s.split(';'):
        k, v = x.split('=')
        d[k] = v
    return d


def p_brian(s):
    return dict(item.split("=") for item in s.split(";"))

def p_kyle(s):
    return urlparse.parse_qs(s)



print "p_easytiger_quoting:" + str(timeit.timeit(lambda: p_easytiger_quoting(s)))
print p_easytiger_quoting(s)


print "p_brian:" + str(timeit.timeit(lambda: p_brian(s)))
print p_brian(s)

print "p_kyle:" + str(timeit.timeit(lambda: p_kyle(s)))
print p_kyle(s)

Điều này không trả lời câu hỏi, bởi vì nó không xử lý trích dẫn. Hãy thử s = "Name1='Value1=2';Name2=Value2" and csv` (như trong câu trả lời được chấp nhận của Brian) hoặc parse_qs(như trong của Kyle) sẽ đúng, trong khi của bạn sẽ tăng a ValueError. OP đặc biệt nói rằng "các giải pháp nhỏ như vậy thường là các mỏ khai thác đang chờ đợi xảy ra", đó là lý do tại sao ông ấy muốn có một giải pháp tích hợp sẵn hoặc giải pháp đã được thử nghiệm tốt khác và ông ấy đưa ra một ví dụ sẽ phá vỡ mã của bạn.
abarnert

Ahh tôi không thấy điều đó. vẫn. nó vẫn sẽ nhanh hơn tất cả các giải pháp của bạn để Chuẩn bị các giải pháp trong chuỗi chính trước khi quá trình lặp diễn ra và gọi lại hàm thay thế hàng nghìn lần. Tôi sẽ cập nhật
easytiger

Tôi không chắc bạn sẽ chuẩn bị nó như thế nào. Nhưng ngay cả khi bạn làm vậy, điều này có vẻ giống chính xác những gì OP đã sợ trong một giải pháp đơn giản. Bạn có chắc là không có mỏ nào khác phía trước không? Bạn có thể chứng minh điều đó với sự hài lòng của OP?
abarnert

OK, bây giờ tôi đã thấy bản chỉnh sửa của bạn… Đầu tiên, s.replacekhông làm gì cả; nó chỉ trả về một chuỗi mới mà bạn bỏ qua. Thứ hai, ngay cả khi bạn đã hiểu đúng ( s = s.replace…), điều đó không khắc phục được sự cố, nó chỉ thêm một cái mới trên đầu trang. Hãy thử nó trên ví dụ của tôi hoặc OP.
abarnert

Đặc tả rõ ràng bao gồm việc xử lý đầu vào mẫu mà anh ta đã đề cập trong câu hỏi của mình , Name='Value1=2';. Và mã của bạn không xử lý nó. Và tôi không chắc làm thế nào bạn làm sạch nó mà không phân tích cú pháp nó theo một cách nào đó sẽ chậm như urlparsehoặc csvngay từ đầu.
abarnert

-2

NẾU Value1, Value2 của bạn chỉ là trình giữ chỗ cho các giá trị thực, bạn cũng có thể sử dụng dict()hàm kết hợp với eval().

>>> s= "Name1=1;Name2=2;Name3='string'"
>>> print eval('dict('+s.replace(';',',')+')')
{'Name2: 2, 'Name3': 'string', 'Name1': 1}

Đây là do dict()hàm hiểu cú pháp dict(Name1=1, Name2=2,Name3='string'). Các dấu cách trong chuỗi (ví dụ: sau mỗi dấu chấm phẩy) bị bỏ qua. Nhưng lưu ý rằng các giá trị chuỗi không yêu cầu trích dẫn.


Cảm ơn, upvote string.replace hoạt động tốt. Không biết tại sao tôi không thể tách ra. Tôi đã thực hiện i = textcontrol.GetValue () trên hộp tc, sau đó o = i.split (';') nhưng không xuất ra một chuỗi chỉ phàn nàn về định dạng, không giống như thay thế.
Iancovici

1
s.replace(';'giải pháp dựa trên phá vỡ nếu có ;bên trong một giá trị được trích dẫn. eval là ác và nó là không cần thiết trong trường hợp này.
jfs
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.