2010-08-04 14 views
9

Realmente me gustaría que mi aplicación Python trate exclusivamente con cadenas Unicode internamente. Esto me ha ido bien últimamente, pero me he encontrado con un problema con las rutas de manejo. La API POSIX para sistemas de archivos no es Unicode, por lo que es posible (y de hecho algo común) que los archivos tengan nombres "indecodificables": nombres de archivos que no están codificados en la codificación establecida del sistema de archivos.¿Cómo manejar nombres de archivo indecodificables en Python?

En Python, esto se manifiesta como una mezcla de unicode y str objetos devueltos desde os.listdir().

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

En ese ejemplo, el carácter '\xe1' está codificado en Latin-1 o algo por el estilo, incluso cuando la (hipotética) de sistema de archivos informa sys.getfilesystemencoding() == 'UTF-8' (en UTF-8, que carácter serían los dos bytes '\xc3\xa1'). Por esta razón, obtendrá UnicodeError s por todas partes si intenta utilizar, por ejemplo, os.path.join() con rutas Unicode, porque el nombre de archivo no se puede decodificar.

El Python Unicode HOWTO ofrece este consejo sobre nombres de ruta Unicode:

Tenga en cuenta que en la mayoría de ocasiones, las API Unicode debe ser utilizado. Las API de bytes solo deben usarse en sistemas donde los nombres de archivos indecodificables pueden estar presentes, es decir, sistemas Unix.

Porque me importa principalmente de los sistemas Unix, ¿significa esto que debería reestructurar mi programa a tratar sólo con cadenas de bytes de caminos? (De ser así, ¿cómo puedo mantener la compatibilidad con Windows?) ¿O hay otras formas mejores de tratar con nombres de archivos indecodificables? ¿Son lo suficientemente raros "en la naturaleza" como para pedirles a los usuarios que renombren sus malditos archivos?

(Si lo mejor es tratar simplemente con cadenas de bytes internamente, tengo una pregunta de seguimiento:? ¿Cómo almaceno cadenas de bytes en SQLite para una columna, manteniendo el resto de los datos de las cadenas Unicode como amigables)

Respuesta

2

Si necesita almacenar cadenas de bytes en un DB que está orientado para UNICODE, entonces probablemente sea más fácil grabar las cadenas de bytes codificadas en hexadecimal. De esta manera, la cadena codificada en hexadecimal es segura de almacenar como una cadena unicode en el DB.

En cuanto a la cuestión del nombre de ruta de acceso de UNIX, entiendo que no existe una codificación específica forzada para los nombres de archivos por lo que es completamente posible tener Latin-1, KOI-8-R, CP1252 y otros en varios archivos. Esto significa que cada componente en una ruta puede tener una codificación separada.

Estaría tentado de intentar adivinar la codificación de nombres de archivo utilizando algo como chardet module. Por supuesto, no hay garantías, por lo que todavía tiene que manejar excepciones, pero tendría menos nombres sin código. Algún software reemplaza los caracteres no codificables por? que no es reversible Prefiero verlos reemplazados con \ xdd o \ xdddd porque pueden invertirse manualmente si es necesario. En algunas aplicaciones, es posible presentar la cadena a un usuario para que pueda introducir caracteres Unicode para reemplazar los caracteres no codificables.

Si avanza por esta ruta, puede terminar extendiendo chardet para manejar este trabajo. Sería bueno complementarlo con una utilidad que escanea un sistema de archivos encontrando nombres no codificables y produce una lista que podría ser editada, luego retroalimentada, para arreglar todos los nombres con equivalentes de Unicode.

+0

+1 para el primer párrafo: la mejor manera de tratar con datos no codificables es evitar la decodificación si es posible. Escanee la lista y codifique todo lo que es un objeto Unicode de nuevo a una cadena de bytes utilizando la codificación del sistema de archivos. Las cadenas de bytes indecodificables existentes deberían permanecer intactas. – detly

+0

Sí; gracias por el consejo. He dado el paso decisivo y pasé a las rutas de cadenas de bytes por completo (al menos para Python 2.x). Para el registro, envolver objetos str en objetos buffer antes de almacenarlos en SQLite evita que se decodifiquen automáticamente como UTF-8. – adrian

Cuestiones relacionadas