Aufteilen einer durch Semikolons getrennten Zeichenfolge in ein Wörterbuch in Python

84

Ich habe eine Zeichenfolge, die so aussieht:

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

Gibt es eine integrierte Klasse / Funktion in Python, die diese Zeichenfolge verwendet und ein Wörterbuch erstellt, als hätte ich dies getan:

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

Ich habe die verfügbaren Module durchgesehen, kann aber anscheinend nichts Passendes finden.


Danke, ich weiß, wie man den relevanten Code selbst erstellt, aber da solche kleinen Lösungen normalerweise Minenfelder sind, die darauf warten, passiert zu werden (dh jemand schreibt: Name1 = 'Wert1 = 2';) usw., bevorzuge ich normalerweise einige Vorab-Felder getestete Funktion.

Ich mache es dann selbst.

Lasse V. Karlsen
quelle
Muss Ihre Frage die s = r'Name1='Value=2';Name2=Value2;Name3=Value3;Name4="Va\"lue;\n3"'Eingabe unterstützen (Hinweis: Ein Semikolon in einer Zeichenfolge in Anführungszeichen, ein Anführungszeichen wird mit einem Backslash maskiert, \nEscape wird verwendet, einfache und doppelte Anführungszeichen werden verwendet)?
JFS
Diese Frage von mir ist über 6 Jahre alt, der Code, der dies betraf, wurde längst ersetzt :) Und nein, es war keine Unterstützung für Zitate erforderlich. Ich wollte nur eine vorgefertigte Funktion haben, anstatt selbst etwas zu schreiben. Der Code ist jedoch schon lange weg.
Lasse V. Karlsen

Antworten:

143

Es gibt kein eingebautes, aber Sie können dies ziemlich einfach mit einem Generatorverständnis erreichen:

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

[Bearbeiten] In Ihrem Update geben Sie an, dass Sie möglicherweise das Zitieren übernehmen müssen. Dies erschwert die Dinge, je nachdem, nach welchem ​​Format Sie genau suchen (welche Anführungszeichen werden akzeptiert, welche Escape-Zeichen usw.). Vielleicht möchten Sie sich das CSV-Modul ansehen, um festzustellen, ob es Ihr Format abdeckt. Hier ein Beispiel: (Beachten Sie, dass die API für dieses Beispiel etwas umständlich ist, da CSV so konzipiert ist, dass es eine Folge von Datensätzen durchläuft, daher die Aufrufe von .next (), die ich mache, um nur die erste Zeile zu betrachten. Anpassen an Ihren Bedürfnissen entsprechen):

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

Abhängig von der genauen Struktur Ihres Formats müssen Sie möglicherweise jedoch Ihren eigenen einfachen Parser schreiben.

Brian
quelle
Der Code verarbeitet keine s = "Name1='Value;2';Name2=Value2;Name3=Value3"Anführungszeichen Name1. Versuchen Sie Folgendes : (Hinweis: Semikolon im angegebenen Wert).
JFS
1
Ich habe keine Ahnung, warum das zweite Beispiel AttributeError: '_csv.reader' object has no attribute 'next'für mich wirft . Natürlich habe ich import csv.
Youngjae
@Brian Gibt es eine Möglichkeit, die Werte als Ganzzahl anstatt als Zeichenfolge zu speichern?
ChasedByDeath
6

Dies kommt dem nahe, was Sie wollten:

>>> import urlparse
>>> urlparse.parse_qs("Name1=Value1;Name2=Value2;Name3=Value3")
{'Name2': ['Value2'], 'Name3': ['Value3'], 'Name1': ['Value1']}
Kyle Gibson
quelle
2
es bricht ab, wenn es &oder %in der Eingabe ist.
JFS
@jfs, aber die Zeichenfolge enthält keine davon.
Vishal Singh
@VishalSingh: Die meisten Besucher auf StackOverflow stammen von Google. Daher beziehen sich die Antworten hier nicht nur auf das Originalposter, das die Frage gestellt hat. Wenn ich hierher gekommen bin, um herauszufinden, wie man eine "durch Semikolons getrennte Zeichenfolge in ein Wörterbuch in Python" analysiert, dann könnten meine Zeichenfolgen enthalten &oder %- zumindest ist es erwähnenswert, dass die Antwort für solche Zeichenfolgen nicht funktioniert.
JFS
3
s1 = "Name1=Value1;Name2=Value2;Name3=Value3"

dict(map(lambda x: x.split('='), s1.split(';')))
D. Om
quelle
1

Dies kann einfach durch String-Join und Listenverständnis erfolgen

",".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'
Vijay
quelle
-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)
ruhig Tiger
quelle
Dies beantwortet die Frage nicht, da das Zitieren nicht möglich ist. Versuchen Sie es mit s = "Name1='Value1=2';Name2=Value2" and csv` (wie in Brians akzeptierter Antwort) oder parse_qs(wie in Kyles), um es richtig zu machen, während Ihr a erhöht ValueError. Das OP sagt ausdrücklich, "solche kleinen Lösungen sind normalerweise Minenfelder, die darauf warten, passiert zu werden", weshalb er eine integrierte oder eine andere gut getestete Lösung wünscht, und er gibt ein Beispiel, das Ihren Code kaputt macht.
abarnert
Ahh das habe ich nicht gesehen. immer noch. Es wäre immer noch schneller als alle Ihre Lösungen, diese in der Hauptzeichenfolge vorzubereiten, bevor die Iteration stattfindet, und die Ersetzungsfunktion tausende Male abzurufen. Ich werde aktualisieren
easytiger
Ich bin mir nicht sicher, wie du es vorbereiten wirst. Aber selbst wenn Sie dies tun, scheint dies genau das zu sein, wovor das OP in einer einfachen Lösung Angst hatte. Sind Sie sicher, dass keine weiteren Minen vor Ihnen liegen? Können Sie es zur Zufriedenheit des OP beweisen?
abarnert
OK, jetzt, wo ich Ihre Bearbeitung gesehen habe ... Erstens, s.replacemacht überhaupt nichts; Es wird nur eine neue Zeichenfolge zurückgegeben, die Sie ignorieren. Zweitens, selbst wenn Sie es richtig verstanden haben ( s = s.replace…), das das Problem nicht behebt, fügt es einfach ein neues hinzu. Probieren Sie es entweder an meinem Beispiel oder an den OPs aus.
Abarnert
Die Spezifikation beinhaltet eindeutig die Behandlung der Probeneingabe, die er in seiner Frage erwähnt hat Name='Value1=2';. Und Ihr Code handhabt es nicht. Und ich bin mir nicht sicher, wie Sie das bereinigen würden, ohne es auf eine Weise zu analysieren, die genauso langsam ist wie urlparseoder csvan erster Stelle.
abarnert
-2

Wenn Ihr Wert1, Wert2 nur Platzhalter für tatsächliche Werte sind, können Sie die dict()Funktion auch in Kombination mit verwenden eval().

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

Dies liegt daran, dass die dict()Funktion die Syntax versteht dict(Name1=1, Name2=2,Name3='string'). Leerzeichen in der Zeichenfolge (z. B. nach jedem Semikolon) werden ignoriert. Beachten Sie jedoch, dass für die Zeichenfolgenwerte Anführungszeichen erforderlich sind.

Rabarberski
quelle
Danke, upvote string.replace hat gut funktioniert. Ich weiß nicht, warum ich mich nicht trennen konnte. Ich habe i = textcontrol.GetValue () auf tc box ausgeführt, dann o = i.split (';'), aber im Gegensatz zu replace keine Zeichenfolge ausgegeben, die sich nur über das Format beschwert hat.
Iancovici
1
s.replace(';'-basierte Lösung bricht ab, wenn sich ;ein Wert in Anführungszeichen befindet. eval ist böse und in diesem Fall unnötig.
jfs