2012-10-27 16 views
10

Eventuali duplicati:
How to get string Objects instead Unicode ones from JSON in Python?Python: Convertire complesso dizionario di stringhe da Unicode a ASCII

Ho un sacco di input come dizionari multi-livello analizzati da chiamate API JSON. Le stringhe sono tutte in unicode, il che significa che c'è un gran numero di u'stuff like this'. Sto usando jq per giocare con i risultati e ho bisogno di convertire questi risultati in ASCII.

So che posso scrivere una funzione per convertire proprio in quel modo:

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 

Questo è anche corretto? Non sono sicuro. Non è quello che voglio chiederti però.

Quello che sto chiedendo è, questa è una tipica soluzione a forza bruta del problema. Ci deve essere un modo migliore. Un modo più pitonico. Non sono esperto di algoritmi, ma anche questo non sembra particolarmente veloce.

Quindi c'è un modo migliore? O se no, questa funzione può essere migliorata ...?


Post-risposta modificare

Mark Amery's answer è corretto ma vorrei pubblicare una versione modificata di esso. La sua funzione di opere su Python 2.7+ e sono il 2.6 così ha dovuto convertirlo:

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

Se si utilizza Python 2, Unicode non è un'istanza di 'str', ma di 'unicode'. Inoltre, nell'elaborazione 'list' e' dict', stai sbagliando. – agf

+0

Per l'elenco dei casi, potrebbe essere opportuno prendere in considerazione la gestione di qualsiasi iterabile. In ogni caso, è possibile sostituire quel ramo dell'istruzione if con 'ret = [convert (x) per x in input]'. Inoltre, controlla il caso del dizionario. 'ret' conterrà solo l'ultima chiave convertita nel dizionario. –

+0

@MichaelMior Il problema con la gestione di qualsiasi iterabile nel modo in cui hai descritto è che non tutti i iterabili sono simili a elenchi. Ad esempio, i dizionari sono iterabili, ma 'ret = [convert (x) per x in input]' non è chiaramente quello che vogliamo se 'input' è un dizionario. –

risposta

23

ricorsione sembra il modo di andare qui, ma se siete in pitone 2.xx si vuole essere il controllo per unicode, non str (il tipo str rappresenta una stringa di byte e il unicode digita una stringa di caratteri Unicode, non eredita dall'altro e si tratta di stringhe di tipo Unicode che vengono visualizzate nell'interprete con au di fronte a esse) .

C'è anche un piccolo errore di sintassi nel codice inviato (la finale elif: dovrebbe essere un else), e non si sta tornando la stessa struttura nel caso in cui ingresso è o un dizionario o una lista. (Nel caso di un dizionario, si restituisce la versione convertita della chiave finale, nel caso di un elenco, si restituisce la versione convertita dell'elemento finale. Né è giusto!)

È possibile anche rendere il codice carino e Pythonic usando le comprensioni.

Ecco, dunque, è quello che mi consiglia:

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 

Un'ultima cosa. Ho cambiato encode('ascii') in encode('utf-8'). Il mio ragionamento è il seguente: qualsiasi stringa unicode che contiene solo caratteri nel set di caratteri ASCII sarà rappresentata dalla stessa stringa di byte quando viene codificata in ASCII come quando è codificata in utf-8, quindi usare utf-8 invece di ASCII non può rompere nulla e la modifica sarà invisibile fintanto che le stringhe Unicode che hai a che fare usano solo caratteri ASCII. Tuttavia, questa modifica estende l'ambito della funzione per essere in grado di gestire stringhe di caratteri dall'intero insieme di caratteri Unicode, piuttosto che solo ASCII, nel caso in cui una cosa del genere fosse mai necessaria.

+1

+1. Tranne che per il commento sulla ricorsione :) La ricorsione è utile per quasi ogni tipo di attraversamento di alberi e la maggior parte dei problemi di analisi. La ricorsione è spesso la "strada da percorrere", specialmente quando si parla di programmazione funzionale. –

+1

@JoelCornett Abbastanza giusto. Il mio commento non intendeva essere ampiamente anti-ricorsione; Vedo che la ricorsione ha senso nei problemi di attraversamento dell'albero, dei quali suppongo che molti problemi di parsing siano un sottoinsieme. Sono un po 'nuovo in questo gioco e non in un contesto compsci, quindi non ho ancora incontrato problemi di natura. Gli esempi di ricorsione che ho visto tendono ad essere inutili e inventati e ad applicarlo a situazioni in cui l'iterazione sarebbe più chiara. Questa è la prima volta che improvvisamente me ne vado 'whoa, la ricorsione * semplifica davvero le cose * qui', il che è stato eccitante per me. :) –

+0

Grazie, questo è davvero bello. Molto meglio di qualsiasi risposta nella domanda che questo è presumibilmente un duplicato di. – Dreen

Problemi correlati