2012-10-27 7 views
10

Mögliche Duplizieren in ASCII:
How to get string Objects instead Unicode ones from JSON in Python?Python: Konvertieren komplexe Wörterbuch von Strings von Unicode

Ich habe viel Input wie Multi-Level-Wörterbücher von JSON-API-Aufrufe analysiert. Die Strings sind alle in Unicode, was bedeutet, dass es viele u'stuff like this' gibt. Ich verwende jq, um mit den Ergebnissen herumzuspielen und diese Ergebnisse in ASCII zu konvertieren.

Ich weiß, dass ich eine Funktion schreiben, kann es einfach so konvertieren:

def convert(input): 
    if isinstance(input, dict): 
     ret = {} 
     for stuff in input: 
      ret = convert(stuff) 
    elif isinstance(input, list): 
     ret = [] 
     for i in range(len(input)) 
      ret = convert(input[i]) 
    elif isinstance(input, str): 
     ret = input.encode('ascii') 
    elif : 
     ret = input 
    return ret 

Ist das auch richtig? Nicht sicher. Das möchte ich dich aber nicht fragen.

Was ich fragen ist, das ist eine typische Brute-Force-Lösung für das Problem. Es muss einen besseren Weg geben. Ein mehr pythonischer Weg. Ich bin kein Experte für Algorithmen, aber dieser sieht auch nicht besonders schnell aus.

Also gibt es einen besseren Weg? Oder wenn nicht, kann diese Funktion verbessert werden ...?


Post-Antwort bearbeiten

Mark Amery's answer korrekt ist, aber ich möchte eine modifizierte Version davon schreiben. Seine Funktion ist auf Python 2.7+ und ich bin auf 2.6, so hatte es zu konvertieren:

def convert(input): 
    if isinstance(input, dict): 
     return dict((convert(key), convert(value)) for key, value in input.iteritems()) 
    elif isinstance(input, list): 
     return [convert(element) for element in input] 
    elif isinstance(input, unicode): 
     return input.encode('utf-8') 
    else: 
     return input 
+1

Wenn Sie in Python 2 sind, dann ist Unicode keine Instanz von 'str', sondern von' unicode'. Auch bei der 'list'- und' dict'-Verarbeitung machen Sie es falsch. – agf

+0

Für den Listenfall möchten Sie möglicherweise die Behandlung von Iterablen berücksichtigen. In jedem Fall können Sie den Zweig der if-Anweisung durch 'ret = [convert (x) for x in input]' ersetzen. Überprüfen Sie auch Ihren Wörterbuchfall. "ret" enthält nur den letzten Schlüssel, in den das Wörterbuch konvertiert. –

+0

@MichaelMior Das Problem bei der Behandlung von iterierbaren Elementen ist, dass nicht alle iterierbaren Elemente listartig sind. Zum Beispiel sind Dictionaries iterierbar, aber 'ret = [convert (x) für x input]' ist eindeutig nicht das, was wir wollen, wenn 'input' ein Dictionary ist. –

Antwort

23

Rekursion scheint, wie die Art und Weise, hier zu gehen, aber wenn Sie auf Python 2.xx sind Sie werden überprüft für unicode, nicht str (der str Typ repräsentiert eine Zeichenfolge von Bytes und der unicode Typ eine Zeichenfolge Unicode-Zeichen; keiner erbt von der anderen und es ist Unicode-Typ Zeichenfolgen, die im Interpreter mit Au vor ihnen angezeigt werden) .

Es gibt auch einen kleinen Syntaxfehler in Ihrem geposteten Code (der nachfolgende elif: sollte ein else sein), und Sie geben nicht die gleiche Struktur in dem Fall zurück, wo Eingabe entweder ein Wörterbuch oder eine Liste ist. (Im Fall eines Wörterbuchs geben Sie die konvertierte Version des endgültigen Schlüssels zurück; im Fall einer Liste geben Sie die konvertierte Version des endgültigen Elements zurück. Das ist auch nicht richtig!)

Sie können Machen Sie Ihren Code auch schön und Pythonic mit Hilfe von Comprehensions.

Hier ist es also, was ich empfehlen würde:

def convert(input): 
    if isinstance(input, dict): 
     return {convert(key): convert(value) for key, value in input.iteritems()} 
    elif isinstance(input, list): 
     return [convert(element) for element in input] 
    elif isinstance(input, unicode): 
     return input.encode('utf-8') 
    else: 
     return input 

Eine letzte Sache. Ich habe encode('ascii') zu encode('utf-8') geändert. Meine Argumentation lautet wie folgt: Jede Unicode-Zeichenfolge, die nur Zeichen im ASCII-Zeichensatz enthält, wird bei ASCII-Codierung durch die gleiche Byte-Zeichenfolge dargestellt wie bei utf-8, sodass die Verwendung von utf-8 anstelle von ASCII nichts aufbrechen kann Die Änderung wird unsichtbar sein, solange die Unicode-Strings, mit denen Sie es zu tun haben, nur ASCII-Zeichen verwenden. Diese Änderung erweitert jedoch den Umfang der Funktion, um Zeichenketten aus dem gesamten Unicode-Zeichensatz und nicht nur ASCII-Zeichensätzen handhaben zu können, sollte dies jemals erforderlich sein.

+1

+1. Außer Sie kommentieren Rekursion :) Rekursion ist nützlich für fast jede Art von Traversal und die meisten Parsing-Probleme. Rekursion ist oft der "Weg zu gehen", besonders wenn es um funktionale Programmierung geht. –

+1

@JoelCornett Fair genug. Mein Kommentar sollte nicht allgemein Anti-Rekursion sein; Ich kann sehen, dass Rekursion in Traversalproblemen von Bedeutung ist, von denen ich denke, dass viele Parsing-Probleme eine Teilmenge sind. Ich bin nur ziemlich neu in diesem Spiel und nicht von einem Computer Hintergrund, so dass ich noch keine Probleme dieser Art selbst begegnet bin. Beispiele für Rekursion, die ich gesehen habe, sind eher sinnlos und künstlich, und wenden sie auf Situationen an, in denen die Iteration klarer wäre. Dies ist das erste Mal, dass ich plötzlich "Whoa, Rekursion * wirklich vereinfacht die Dinge * hier", was für mich spannend war. :) –

+0

Danke, das ist wirklich nett. Viel besser als jede Antwort in der Frage, dass es sich angeblich um ein Duplikat handelt. – Dreen

Verwandte Themen