2012-03-18 12 views
15

Mając trochę zmagań z nazwami plików w Unicode w OS X i Pythonie. Próbuję użyć nazw plików jako danych wejściowych dla wyrażenia regularnego później w kodzie, ale kodowanie używane w nazwach plików wydaje się być inne niż to, co mówi mi sys.getfilesystemencoding(). Weźmy następujący kod:Kodowanie Unicode dla systemu plików w Mac OS X nie jest poprawne w Pythonie?

#!/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 

To wyprowadza następujące:

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

Tak, kodowanie system plików jest UTF-8, ale kiedy kodować mojego pliku AAO użyciu, że to nie będzie takie samo tak jakbym tworzył nazwę katalogu z tym samym ciągiem znaków. Spodziewam się, że kiedy użyję swojego ciągu åäö do stworzenia katalogu i odczytam jego nazwę, powinien on używać tych samych kodów, co w przypadku bezpośredniego zastosowania kodowania.

Jeśli spojrzymy na punkty kodowe 97, 778, 97, 776, 111, 776, to w zasadzie znaki ASCII z dodanym znakiem diakrytycznym, np. o + ¨ = ö, co sprawia, że ​​jest to dwa znaki, a nie jeden. Jak mogę uniknąć tej rozbieżności, czy w Pythonie jest taki schemat kodowania, który pasuje do tego zachowania systemu OS X, i dlaczego getfilesystemencoding() nie daje właściwego wyniku?

A może coś zepsułem?

+0

Problem można rozwiązać na tych szczególnych znaków, wykonując po wyrażeniu regularnym ciągów nazw plików, aby uzyskać je w postaci unicode bez znaków diakrytycznych: '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

Odpowiedz

24

MacOS X używa specjalnego rodzaju rozłożonego UTF-8 do przechowywania nazw plików. Jeśli potrzebujesz np. czytaj w nazwach plików i zapisuje je do „normalnego” UTF-8 pliku, należy je normalizować:

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

stąd: https://web.archive.org/web/20120423075412/http://boodebr.org/main/python/all-about-python-and-unicode

+0

Przeszedł na ten problem z node.js pakiet npm 'unorm' ma naprawdę ładny interfejs do tego. – mmilleruva

17

getfilesystemencoding() daje Ci prawidłową odpowiedź (kodowanie ) ale nie oznacza to, że unicode normalisation form.

W szczególności system plików HFS + wykorzystuje kodowanie UTF-8, a formularz normalizacji zbliża się do litery "D" (co wymaga złożenia znaków takich jak ö, które mają zostać rozłożone na ). HFS + jest również powiązany z formularzem normalizacji, tak jak istniało w Unicode w wersji 3.2 - jak to opisano w Apple's documentation for the HFS+ format.

Pythona unicodedata.normalize metoda konwertuje pomiędzy formami, a jeśli prefiks połączenia z obiektem ucd_3_2_0 można ograniczyć go do wersji Unicode 3.2:

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

Dzięki, świetna odpowiedź, żałuję, że nie mogłem przegłosować i zaakceptować obu odpowiedzi! – RipperDoc

+2

Właściwie to nie całkiem NFD, ale jest blisko. – tchrist

Powiązane problemy