Python'da noktalı virgülle ayrılmış bir dizeyi sözlüğe bölme


86

Şuna benzeyen bir dizem var:

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

Python'da, bunu ben yapmışım gibi, bu dizeyi alacak ve bir sözlük oluşturacak yerleşik bir sınıf / işlev var mı:

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

Mevcut modülleri inceledim, ancak eşleşen bir şey bulamıyorum.


Teşekkürler, ilgili kodu nasıl yapacağımı biliyorum, ancak bu tür küçük çözümler genellikle gerçekleşmeyi bekleyen mayın tarlaları olduğundan (yani birisi şunu yazıyor: İsim1 = 'Değer1 = 2';) vb. O zaman genellikle bazı ön test edilmiş fonksiyon.

O zaman kendim yaparım.


Sorunuz s = r'Name1='Value=2';Name2=Value2;Name3=Value3;Name4="Va\"lue;\n3"'girdiyi desteklemeyi gerektiriyor mu (not: tırnak içine alınmış bir dizge içinde bir noktalı virgül, ters eğik çizgi kullanılarak bir alıntı öncelenir, \nkaçış kullanılır, hem tek hem de çift tırnak kullanılır)?
jfs

Bu sorum 6 yaşın üzerinde, bunu içeren kod çoktan değiştirildi :) Ve hayır, alıntılar için destek gerektirmiyordu. Kendim bir şeyler yazmak yerine önceden oluşturulmuş bir işleve sahip olmak istedim. Ancak, kod çoktan gitti.
Lasse V.Karlsen

Yanıtlar:


145

Yerleşik yoktur, ancak bunu oldukça basit bir üreteç anlayışı ile başarabilirsiniz:

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

[Düzenle] Güncellemenizden alıntı yapmanız gerekebileceğini belirtmişsiniz. Bu, tam olarak aradığınız formatın ne olduğuna bağlı olarak işleri karmaşıklaştırır (hangi alıntı karakterleri kabul edilir, hangi kaçış karakterleri vb.). Formatınızı kapsayıp kapsamayacağını görmek için csv modülüne bakmak isteyebilirsiniz. İşte bir örnek: (API'nin bu örnek için biraz hantal olduğuna dikkat edin, çünkü CSV bir dizi kayıt boyunca yineleme yapacak şekilde tasarlandığından, sadece ilk satıra bakmak için yaptığım .next () çağrıları. ihtiyaçlarınıza uygun):

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

Formatınızın tam yapısına bağlı olarak, kendi basit ayrıştırıcınızı yazmanız gerekebilir.


kod alıntı yapmaz, deneyin: s = "Name1='Value;2';Name2=Value2;Name3=Value3"(not: alıntılanan Name1değerde noktalı virgül ).
jfs

1
İkinci örneğin neden AttributeError: '_csv.reader' object has no attribute 'next'benim için uygun olduğuna dair hiçbir fikrim yok . Tabii ki yaptım import csv.
Youngjae

@Brian Değerleri string yerine tamsayı olarak saklamanın bir yolu var mı?
ChasedByDeath

tersini nasıl yapabilirim @Brain
Jamil Noyda

6

Bu, istediğiniz şeyi yapmaya çok yaklaşıyor:

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

2
varsa &veya %girişte varsa kırılır .
jfs

@jfs, ancak dize bunlardan hiçbirini içermiyor.
Vishal Singh

@VishalSingh: StackOverflow'daki çoğu ziyaretçi google'dan geliyor ve bu nedenle buradaki yanıtlar yalnızca soruyu soran orijinal gönderen için değil. Buraya "noktalı virgülle ayrılmış bir dizeyi Python'da bir sözlüğe" nasıl ayrıştıracağımı aramaya geldiysem, dizelerim şunları içerebilir &veya %- en azından, yanıtın bu tür dizeler için işe yaramadığını belirtmek gerekir.
jfs

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

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

1

Dize birleştirme ve liste anlama ile basitçe yapılabilir

",".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)

Bu soruya cevap vermez, çünkü alıntı yapmayı becermez. s = "Name1='Value1=2';Name2=Value2" and Csv`'yi deneyin (Brian'ın kabul ettiği cevapta parse_qsolduğu gibi ) veya ( Kyle'ınki gibi ) doğru yapacaktır, sizinkiler a yükseltecektir ValueError. OP özellikle "bu tür küçük çözümler genellikle gerçekleşmeyi bekleyen mayın tarlalarıdır" diyor, bu yüzden yerleşik veya iyi test edilmiş başka bir çözüm istiyor ve kodunuzu kıracak bir örnek veriyor.
abarnert

Ahh bunu görmedim. hala. Yineleme gerçekleşmeden önce ana dizede bulunanları hazırlamak ve değiştirme işlevini binlerce kez geri çağırmak hala tüm çözümlerinizden daha hızlı olacaktır. Güncelleyeceğim
easytiger

Nasıl hazırlayacağından emin değilim. Ama yapsanız bile, bu tam olarak OP'nin basit bir çözümde korktuğu gibi görünüyor. İleride başka mayın olmadığına emin misin? OP'nin memnuniyetini kanıtlayabilir misin?
abarnert

Tamam, şimdi düzenlemenizi gördüm… İlk olarak, s.replacehiçbir şey yapmıyor; sadece göz ardı ettiğiniz yeni bir dize döndürür. İkincisi, doğru yapsanız bile ( s = s.replace…), bu sorunu çözmez, sadece üstüne yeni bir tane ekler. Ya benim örneğimde ya da OP'lerde deneyin.
abarnert

Spesifikasyon, sorusunda bahsettiği örnek girdinin ele alınmasını açıkça içerir Name='Value1=2';. Ve kodunuz bunu idare etmiyor. Ve ilk etapta urlparseya csvda en az onun kadar yavaş olacak bir şekilde ayrıştırmadan bunu nasıl sterilize edeceğinizden emin değilim .
abarnert

-2

Değer1, Değer2 yalnızca gerçek değerler için yer tutucularsa, dict()işlevi ile birlikte de kullanabilirsiniz eval().

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

Bu, dict()işlevin sözdizimini anlamasıdır dict(Name1=1, Name2=2,Name3='string'). Dizedeki boşluklar (örneğin, her noktalı virgülden sonra) yok sayılır. Ancak dize değerlerinin alıntı gerektirdiğini unutmayın.


Teşekkürler, string.replace olumlu oy kullandı. Neden ayrılamadığımı bilmiyorum. Tc kutusunda i = textcontrol.GetValue () yaptım, sonra o = i.split (';') yaptım, ancak değiştirmenin aksine format hakkında şikayet edilen bir dizge çıktılamadı.
Iancovici

1
s.replace(';';alıntılanan bir değerin içinde varsa-tabanlı çözüm bozulur . eval kötüdür ve bu durumda gereksizdir.
jfs
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.