2012-03-18 34 views
15

Có một chút đấu tranh với tên tệp Unicode trong OS X và Python. Tôi đang cố gắng sử dụng tên tập tin như là đầu vào cho một biểu thức chính quy sau này trong mã, nhưng mã hóa được sử dụng trong tên tập tin dường như khác với những gì sys.getfilesystemencoding() nói với tôi. Đi đoạn mã sau:Mã hóa Unicode cho hệ thống tập tin trong Mac OS X không chính xác trong 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 

Nó ra như sau:

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

Vì vậy, hệ thống tập tin mã hóa là utf-8, nhưng khi tôi mã hóa tên tập tin của tôi AAO sử dụng đó, nó sẽ không giống nhau như thể tôi tạo một tên dir với cùng một chuỗi. Tôi hy vọng rằng khi tôi sử dụng chuỗi åäö của tôi để tạo ra một thư mục, và đọc tên của nó trở lại, nó nên sử dụng các mã giống như tôi đã áp dụng mã hóa trực tiếp.

Nếu chúng ta xem xét các điểm mã 97, 778, 97, 776, 111, 776, về cơ bản các ký tự ASCII có dấu phụ được thêm vào, ví dụ: o + ¨ = ö, mà làm cho nó hai nhân vật, không phải một. Làm thế nào tôi có thể tránh sự khác biệt này, là có một chương trình mã hóa trong Python phù hợp với hành vi này của OS X, và tại sao không phải là getfilesystemencoding() cho tôi kết quả đúng?

Hoặc tôi đã sai lầm?

+0

Vấn đề có thể được giải quyết đối với những nhân vật cụ thể, bằng cách làm như sau regexp trên chuỗi tên tập tin để có được chúng vào unicode diacritic ít hơn: '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

Trả lời

24

MacOS X sử dụng một loại đặc biệt bị phân hủy UTF-8 để lưu trữ tên tệp. Nếu bạn cần, ví dụ: đọc trong tên tập tin và viết chúng vào một "bình thường" tập tin UTF-8, bạn phải bình thường hóa chúng:

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

từ đây: https://web.archive.org/web/20120423075412/http://boodebr.org/main/python/all-about-python-and-unicode

+0

Chạy vào vấn đề này với node.js gói npm 'unorm' có giao diện thực sự tốt đẹp cho việc này. – mmilleruva

17

getfilesystemencoding() được đem lại cho bạn câu trả lời đúng (mã hóa ), nhưng nó không cho bạn biết unicode normalisation form.

Cụ thể, hệ thống tệp HFS + sử dụng mã hóa UTF-8 và biểu mẫu bình thường gần "D" (yêu cầu các ký tự được tạo thành như ö được phân tách thành ). HFS + cũng được gắn với dạng bình thường hóa như nó tồn tại trong phiên bản Unicode 3.2 — như được mô tả chi tiết trong số documentation for the HFS+ format của Apple.

phương pháp unicodedata.normalize Python của chuyển đổi giữa các loại hình, và nếu bạn có tiền tố cuộc gọi với đối tượng ucd_3_2_0, bạn có thể hạn chế nó để Unicode phiên bản 3.2:

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

Cảm ơn, câu trả lời tuyệt vời, ước gì tôi có thể upvote và chấp nhận cả hai câu trả lời! – RipperDoc

+2

Trên thực tế, nó không phải là khá NFD, nhưng nó gần gũi. – tchrist

Các vấn đề liên quan