Mam ciąg, który wygląda tak:
"Name1=Value1;Name2=Value2;Name3=Value3"
Czy w Pythonie jest wbudowana klasa / funkcja, która pobierze ten ciąg i skonstruuje słownik, tak jakbym to zrobił:
dict = {
"Name1": "Value1",
"Name2": "Value2",
"Name3": "Value3"
}
Przejrzałem dostępne moduły, ale nie mogę znaleźć niczego, co pasowałoby.
Dzięki, wiem, jak samemu stworzyć odpowiedni kod, ale ponieważ takie małe rozwiązania to zwykle pola minowe czekające na wystąpienie (np. Ktoś pisze: Name1 = 'Value1 = 2';) itd., To zwykle wolę trochę wcześniej sprawdzona funkcja.
Wtedy zrobię to sam.
python
string
dictionary
split
Lasse V. Karlsen
źródło
źródło
s = r'Name1='Value=2';Name2=Value2;Name3=Value3;Name4="Va\"lue;\n3"'
danych wejściowych (uwaga: średnik w ciągu cytowanym, cudzysłów jest poprzedzony ukośnikiem odwrotnym,\n
używana jest ucieczka, używane są zarówno pojedyncze, jak i podwójne cudzysłowy)?Odpowiedzi:
Nie ma wbudowanej funkcji, ale można to osiągnąć w dość prosty sposób za pomocą zrozumienia generatora:
s= "Name1=Value1;Name2=Value2;Name3=Value3" dict(item.split("=") for item in s.split(";"))
[Edytuj] Ze swojej aktualizacji wskazałeś, że może zajść potrzeba obsługi cytowania. To komplikuje sprawę, w zależności od tego, jakiego dokładnie formatu szukasz (jakie znaki cudzysłowu są akceptowane, jakie znaki ucieczki itp.). Możesz spojrzeć na moduł csv, aby sprawdzić, czy może on pokryć twój format. Oto przykład: (Zauważ, że API jest trochę niezgrabne w tym przykładzie, ponieważ CSV jest zaprojektowany do iteracji przez sekwencję rekordów, stąd wywołania .next (), które wykonuję, aby spojrzeć na pierwszą linię. Dostosuj do do Twoich potrzeb):
>>> 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'}
Jednak w zależności od dokładnej struktury twojego formatu może być konieczne napisanie własnego prostego parsera.
źródło
s = "Name1='Value;2';Name2=Value2;Name3=Value3"
(uwaga: średnik w cytowanejName1
wartości).AttributeError: '_csv.reader' object has no attribute 'next'
mi się. Oczywiście, że takimport csv
.To jest bliskie zrobienia tego, co chciałeś:
>>> import urlparse >>> urlparse.parse_qs("Name1=Value1;Name2=Value2;Name3=Value3") {'Name2': ['Value2'], 'Name3': ['Value3'], 'Name1': ['Value1']}
źródło
&
lub%
na wejściu.&
lub%
- przynajmniej warto wspomnieć, że odpowiedź nie działa dla takich ciągów.s1 = "Name1=Value1;Name2=Value2;Name3=Value3" dict(map(lambda x: x.split('='), s1.split(';')))
źródło
Można to zrobić po prostu za pomocą łączenia łańcuchów i rozumienia listy
",".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'
źródło
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)
źródło
s = "Name1='Value1=2';Name2=Value2" and
csv` (jak w zaakceptowanej odpowiedzi Briana) lubparse_qs
(jak w przypadku Kyle'a) da się to poprawnie, podczas gdy twój podniesieValueError
. OP wyraźnie mówi, że „takie małe rozwiązania to zwykle pola minowe czekające, aby się wydarzyć”, dlatego chce wbudowanego lub innego dobrze przetestowanego rozwiązania i podaje przykład, który złamie twój kod.s.replace
ogóle nic nie robi; po prostu zwraca nowy ciąg, który zignorujesz. Po drugie, nawet jeśli zrobisz to dobrze (s = s.replace…
), to nie rozwiązuje problemu, po prostu dodaje nowy. Wypróbuj na moim przykładzie lub na OP.Name='Value1=2';
. Twój kod tego nie obsługuje. I nie jestem pewien, jak byś to odkażał bez analizowania go w jakiś sposób, który będzie tak samo powolny, jakurlparse
lubcsv
w pierwszej kolejności.JEŚLI Twoja Wartość1, Wartość2 to tylko symbole zastępcze dla rzeczywistych wartości, możesz również użyć tej
dict()
funkcji w połączeniu zeval()
.>>> s= "Name1=1;Name2=2;Name3='string'" >>> print eval('dict('+s.replace(';',',')+')') {'Name2: 2, 'Name3': 'string', 'Name1': 1}
Dzieje się tak, ponieważ
dict()
funkcja rozumie składniędict(Name1=1, Name2=2,Name3='string')
. Spacje w ciągu znaków (np. Po każdym średniku) są ignorowane. Zwróć jednak uwagę, że wartości łańcuchowe wymagają cytowania.źródło
s.replace(';'
rozwiązanie oparte;
na cudzysłowach nie działa, jeśli wewnątrz wartości znajduje się cudzysłów. eval jest zły i w tym przypadku jest niepotrzebny.