2012-06-13 14 views
5

Il mio background è in Perl, ma sto dando a Python plus BeautifulSoup una prova per un nuovo progetto.Python, .format() e UTF-8

In questo esempio, sto cercando di estrarre e presentare i target di collegamento e il testo del collegamento contenuto in una singola pagina. Ecco la fonte:

table_row = u'<tr><td>{}</td><td>{}</td></tr>'.encode('utf-8') 
link_text = unicode(link.get_text()).encode('utf-8') 
link_target = link['href'].encode('utf-8') 
line_out = unicode(table_row.format(link_text, link_target)) 

tutte quelle chiamate esplicite per .encode ('utf-8') sono il mio tentativo di fare questo lavoro, ma non sembra aiutare - è probabile che io sia completamente fraintendere qualcosa su come Python 2.7 gestisce le stringhe Unicode.

In ogni caso. Funziona bene fino a quando non incontra U + 2013 in un URL (sì, davvero). A quel punto le bombe fuori con:

Traceback (most recent call last): 
File "./test2.py", line 30, in <module> 
    line_out = unicode(table_row.encode('utf-8').format(link_text, link_target.encode('utf-8'))) 
    UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 79: ordinal not in range(128) 

Presumibilmente .format(), anche applicata a una stringa Unicode, sta giocando Silly-incula e cercando di fare un'operazione .decode(). E come ASCII è il default, lo sta usando, e ovviamente non può mappare U + 2013 a un carattere ASCII, e quindi ...

Le opzioni sembrano essere di rimuoverlo o convertirlo in qualcos'altro , ma in realtà quello che voglio è semplicemente conservarlo. In definitiva (questo è solo un piccolo caso di test) Devo essere in grado di presentare link cliccabili funzionanti.

La documentazione di BS3 suggerisce di cambiare la codifica predefinita da ASCII a UTF-8 ma di leggere commenti su domande simili che sembrano essere davvero una pessima idea in quanto distruggeranno i dizionari.

A parte l'uso di Python 3.2 (che non significa Django, che stiamo considerando per una parte di questo progetto) c'è un modo per rendere questo lavoro pulito?

+0

come regola di base del pollice, decodificare (a Unicode) sull'ingresso e codificare (per la codifica desiderata) in uscita. – monkut

risposta

8

In primo luogo, si noti che i due esempi di codice non sono d'accordo sul testo della riga problematica:

line_out = unicode(table_row.encode('utf-8').format(link_text, link_target.encode('utf-8'))) 

vs

line_out = unicode(table_row.format(link_text, link_target)) 

Il primo è quello della traceback, quindi è quello di guarda a. Supponendo che il resto del tuo primo esempio di codice sia accurato, table_row è una stringa di byte, perché hai preso una stringa unicode e l'hai codificata. Le stringhe dei byte non possono essere codificate, quindi Python 2 converte implicitamente table_row da byte-string in unicode decodificandolo come ascii. Da qui il messaggio di errore "UnicodeDecodeError from ascii".

È necessario decidere quali stringhe saranno stringhe di byte e quali stringhe Unicode essere disciplinate. Raccomando di mantenere tutto il testo come stringhe Unicode il più possibile.

Ecco una presentazione ho dato a PyCon che spiega tutto: Pragmatic Unicode, or, How Do I Stop The Pain?

+0

Aha. Va bene, grazie. Sembra che un precedente tentativo di comprendere ciò abbia portato al mio attaccare .encode() ovunque, senza rendermi conto che questo sarebbe stato convertito da una stringa Unicode a una stringa di byte. Rimuovere tutti quelli sembra aver risolto il problema! –

+0

Inoltre, mea culpa sui frammenti di codice incoerenti. Ho selezionato le righe pertinenti dal codice così com'è e l'errore di una precedente esecuzione che aveva avuto lo stesso problema. –

+0

Questa presentazione è così buona! Grazie per aver condiviso (e per averlo dato!). –