Есть проблема:
на диске лежит файл "андрей.png"
Мы пытаемся открыть этот файл (код на пайтоне, f = open("андрей.png",'r'))
пример отлично отрабатывает на Mac OSX, однако если перенести файл и скрипт на Linux (Ubuntu) то файл не открывается, пишет что не найден. Здорово?
Здорово. Я раньше думал, с юникодом все просто. Ан нет. "и краткое" может быть закодировано в utf-8 двумя различными способами - с акцентом или без. Остальные диакритические символы с галочками, крыжиками и умляутами - тоже.
при этом, "по умолчанию" разные операционные системы используют разные пути нормализации юникодных имен файлов - Linux, Windows и другие системы используют NFC (нормальная форма С, символ с акцентом - один знак), MacOS - NFD (нормальная форма D, акценты отдельно от символа). один и тот же символ Й, закодированный в разных нормальных формах - это два разных набора бит (на примере UTF-8)
И как следствие, файл не находится, если он записан например в NFC, а в open() передана строка в NFD. Такая вот гадость на ровном практически месте.
Есть несколько способов решить проблему. мне нравится способ отказаться от юникода в именах файлов вообще (pip install unidecode и пользуйся на здоровье).
Либо для кросс-платформенности использовать unicodedata и делать две попытки открыть файл - один с normalize(NFC) а другой - с normalize(NFD)
по второму варианту - вот такая простая функция
ссылки по теме
- википедия http://en.wikipedia.org/wiki/Unicode_normalization
- статейка http://vemod.net/filenames-and-unicode-normalization-forms
- про эти же грабли http://nedbatchelder.com/blog/201106/filenames_with_accents.html
на диске лежит файл "андрей.png"
Мы пытаемся открыть этот файл (код на пайтоне, f = open("андрей.png",'r'))
пример отлично отрабатывает на Mac OSX, однако если перенести файл и скрипт на Linux (Ubuntu) то файл не открывается, пишет что не найден. Здорово?
Здорово. Я раньше думал, с юникодом все просто. Ан нет. "и краткое" может быть закодировано в utf-8 двумя различными способами - с акцентом или без. Остальные диакритические символы с галочками, крыжиками и умляутами - тоже.
при этом, "по умолчанию" разные операционные системы используют разные пути нормализации юникодных имен файлов - Linux, Windows и другие системы используют NFC (нормальная форма С, символ с акцентом - один знак), MacOS - NFD (нормальная форма D, акценты отдельно от символа). один и тот же символ Й, закодированный в разных нормальных формах - это два разных набора бит (на примере UTF-8)
- NFC: "\xd0\xb9"
- NFD: "\xd0\xb8\xcc\x86"
И как следствие, файл не находится, если он записан например в NFC, а в open() передана строка в NFD. Такая вот гадость на ровном практически месте.
Есть несколько способов решить проблему. мне нравится способ отказаться от юникода в именах файлов вообще (pip install unidecode и пользуйся на здоровье).
Либо для кросс-платформенности использовать unicodedata и делать две попытки открыть файл - один с normalize(NFC) а другой - с normalize(NFD)
по второму варианту - вот такая простая функция
# check for unicode
# it supports unicode normal forms NFC and NFD
# see here: http://yuryskaletskiy.blogspot.ru/2014/02/blog-post.html
# returns properly normalized filename if file exists, otherwise None
def unicode_filename_check(name):
name_u = name
if not isinstance(name, unicode):
name_u = name.decode('utf-8')
if os.path.isfile(name_u):
return name_u
#try with NFC
name_u = normalize('NFC', name_u)
if os.path.isfile(name_u):
return name_u
#try with NFD
name_u = normalize('NFD', name_u)
if os.path.isfile(name_u):
return name_u
return None
ссылки по теме
- википедия http://en.wikipedia.org/wiki/Unicode_normalization
- статейка http://vemod.net/filenames-and-unicode-normalization-forms
- про эти же грабли http://nedbatchelder.com/blog/201106/filenames_with_accents.html
Комментариев нет:
Отправить комментарий