2012-03-18 8 views
15

Tener problemas con los nombres de archivo Unicode en OS X y Python. Intento utilizar nombres de archivo como entrada para una expresión regular más adelante en el código, pero la codificación utilizada en los nombres de archivo parece ser diferente de lo que me dice sys.getfilesystemencoding(). Tomemos el siguiente código:La codificación Unicode para el sistema de archivos en Mac OS X no es correcta en Python?

#!/usr/bin/env python 
# coding=utf-8 

import sys,os 
print sys.getfilesystemencoding() 

p = u'/temp/s/' 
s = u'åäö' 
print 's', [ord(c) for c in s], s 
s2 = s.encode(sys.getfilesystemencoding()) 
print 's2', [ord(c) for c in s2], s2 
os.mkdir(p+s) 
for d in os.listdir(p): 
    print 'dir', [ord(c) for c in d], d 

Se muestra la siguiente información:

utf-8 
s [229, 228, 246] åäö 
s2 [195, 165, 195, 164, 195, 182] åäö 
dir [97, 778, 97, 776, 111, 776] åäö 

Por lo tanto, la codificación del sistema de archivos es UTF-8, pero cuando puedo codificar mi nombre AAO utilizando eso, no será la misma como si creara un nombre de directorio con la misma cadena. Espero que cuando use mi cadena åäö para crear un directorio y leer su nombre de nuevo, use los mismos códigos que si aplicara la codificación directamente.

Si miramos los puntos de código 97, 778, 97, 776, 111, 776, básicamente son caracteres ASCII con signos diacríticos añadidos, p. o + ¨ = ö, que lo hace dos caracteres, no uno. ¿Cómo puedo evitar esta discrepancia? ¿Existe un esquema de codificación en Python que coincida con este comportamiento de OS X y por qué getfilesystemencoding() no me da el resultado correcto?

¿O me he equivocado?

+0

El problema puede ser resuelto por esos caracteres específicos, haciendo lo Seguir expresiones regulares en cadenas de nombre de archivo para obtenerlas en unicode diacrítico: 'm_aa = re.compile (ur" a \ u0308 ", re.I), m_ae = re.compile (ur" a \ u030a ", re.I) , m_oe = re.compile (ur "o \ u0308", re.I) – RipperDoc

Respuesta

24

MacOS X utiliza un tipo especial de UTF-8 descompuesto para almacenar nombres de archivos. Si necesita, por ejemplo, leído en los nombres de archivo y escribirlos en un UTF-8 archivo "normal", es necesario normalizarlos:

filename = unicodedata.normalize('NFC', unicode(filename, 'utf-8')).encode('utf-8') 

desde aquí: https://web.archive.org/web/20120423075412/http://boodebr.org/main/python/all-about-python-and-unicode

+0

Se metió en este problema con node.js el paquete npm 'unorm' tiene una interfaz muy buena para esto. – mmilleruva

17

getfilesystemencoding() le está dando la respuesta correcta (la codificación), pero no te dice el unicode normalisation form.

En particular, el sistema de archivos HFS + usa codificación UTF-8 y una forma de normalización cercana a "D" (que requiere caracteres compuestos como ö para descomponerse en ). HFS + también está vinculado al formulario de normalización tal como existía en Unicode versión 3.2, como se detalla en el documentation for the HFS+ format de Apple.

método de Python unicodedata.normalize convierte entre las formas, y si el prefijo de la llamada con el objeto ucd_3_2_0, puede limitarla a Unicode versión 3.2:

filename = unicodedata.ucd_3_2_0.normalize('NFC', unicode(filename, 'utf-8')).encode('utf-8') 
+0

¡Gracias, gran respuesta, desearía poder votar y aceptar ambas respuestas! – RipperDoc

+2

En realidad, no es bastante NFD, pero está cerca. – tchrist