2010-08-04 8 views
9

Mi piacerebbe davvero che la mia applicazione Python venisse trattata esclusivamente con stringhe Unicode internamente. Ultimamente questo è andato bene per me, ma ho riscontrato un problema con i percorsi di gestione. L'API POSIX per i filesystem non è Unicode, quindi è possibile (e in realtà un po 'comune) che i file abbiano nomi "non codificabili": nomi di file che non sono codificati nella codifica dichiarata del file system.Come gestire nomi di file indecifrabili in Python?

In Python, questo si manifesta come una miscela di unicode e str oggetti restituiti da os.listdir().

>>> os.listdir(u'/path/to/foo') 
[u'bar', 'b\xe1z'] 

In questo esempio, il carattere '\xe1' è codificato in latino-1 o somesuch, anche quando la (ipotetica) file system riporta sys.getfilesystemencoding() == 'UTF-8' (UTF-8, che carattere sarebbero i due byte '\xc3\xa1'). Per questo motivo, otterrai UnicodeError dappertutto se si tenta di utilizzare, ad esempio, os.path.join() con percorsi Unicode, poiché il nome file non può essere decodificato.

Il Python Unicode HOWTO offre questo consigli su percorsi unicode:

Nota che nella maggior parte delle occasioni, le API Unicode dovrebbe essere usato. Le API dei byte dovrebbero essere utilizzate solo su sistemi in cui possono essere presenti nomi di file non decodificabili, ad esempio i sistemi Unix.

Poiché mi interessa principalmente i sistemi Unix, significa che dovrei ristrutturare il mio programma per gestire solo i bytestrings per i percorsi? (In tal caso, come posso mantenere la compatibilità con Windows?) O ci sono altri modi migliori per gestire nomi di file non codificabili? Sono abbastanza rari "in the wild" che dovrei solo chiedere agli utenti di rinominare i loro dannati file?

(Se è meglio trattare solo con le stringhe di byte internamente, Ho una domanda followup:? Come faccio a memorizzare stringhe di byte in SQLite per una colonna, mantenendo il resto dei dati di stringhe Unicode come amichevoli)

risposta

2

Se è necessario memorizzare i byte in un DB orientato per UNICODE, quindi è probabilmente più facile registrare i byte codificati in hex. In questo modo, la stringa con codifica esadecimale è sicura da memorizzare come stringa unicode nel db.

Per quanto riguarda il problema del percorso UNIX, la mia comprensione è che non è stata applicata alcuna codifica particolare per i nomi di file, quindi è del tutto possibile avere Latin-1, KOI-8-R, CP1252 e altri su vari file. Ciò significa che ogni componente in un percorso potrebbe avere una codifica separata.

Sarei tentato di provare a indovinare la codifica dei nomi di file utilizzando qualcosa come chardet module. Naturalmente, non ci sono garanzie, quindi devi ancora gestire le eccezioni, ma avresti meno nomi non decodificabili. Alcuni software sostituiscono i caratteri non modificabili con? che non è reversibile. Preferisco vederli sostituiti con \ xdd o \ xdddd perché può essere invertito manualmente se necessario. In alcune applicazioni può essere possibile presentare la stringa a un utente in modo che possano inserire caratteri unicode per sostituire quelli non in grado di essere codificati.

Se si percorre questa strada, è possibile che si estenda chardet per gestire questo lavoro. Sarebbe bello integrarlo con un'utilità che analizza un filesystem trovando nomi non modificabili e produce un elenco che può essere modificato, quindi aggiornato, per correggere tutti i nomi con equivalenti unicode.

+0

+1 per il primo paragrafo: il modo migliore per gestire dati non codificabili è evitare di decodificarlo se possibile. Analizza l'elenco e codifica tutto ciò che è un oggetto Unicode su una stringa di byte utilizzando la codifica del filesystem. Le stringhe di byte non codificabili esistenti dovrebbero rimanere intatte. – detly

+0

Sì; grazie per il consiglio. Ho fatto il grande passo e passato completamente ai percorsi delle stringhe di byte (almeno per Python 2.x). Per la cronaca, il wrapping degli oggetti str negli oggetti buffer prima di memorizzarli in SQLite impedisce loro di essere automaticamente decodificati come UTF-8. – adrian