Os.path в Python задыхается от имен файлов на иврите - PullRequest
14 голосов
/ 31 января 2009

Я пишу сценарий, который должен перемещать некоторые файлы, но, к сожалению, кажется, что os.path не очень хорошо работает с интернационализацией. Когда у меня есть файлы с именами на иврите, возникают проблемы. Вот скриншот содержимого каталога:

alt text
(источник: thegreenplace.net )

Теперь рассмотрим этот код, который просматривает файлы в этом каталоге:

files = os.listdir('test_source')

for f in files:
    pf = os.path.join('test_source', f)
    print pf, os.path.exists(pf)

Вывод:

test_source\ex True
test_source\joe True
test_source\mie.txt True
test_source\__()'''.txt True
test_source\????.txt False

Обратите внимание, как os.path.exists считает, что файл с древнееврейским именем даже не существует? Как я могу это исправить?

ActivePython 2.5.2 в Windows XP Home SP2

Ответы [ 4 ]

17 голосов
/ 31 января 2009

Хм, после некоторое копание кажется, что при подаче os.listdir строки в юникоде это вроде работает:

files = os.listdir(u'test_source')

for f in files:

    pf = os.path.join(u'test_source', f)
    print pf.encode('ascii', 'replace'), os.path.exists(pf)

===>

test_source\ex True
test_source\joe True
test_source\mie.txt True
test_source\__()'''.txt True
test_source\????.txt True

Некоторые важные замечания здесь:

  • Windows XP (как и все производные NT) хранит все имена файлов в юникоде
  • os.listdir (и аналогичным функциям, таким как os.walk) должна быть передана строка Unicode для правильной работы с путями Unicode. Вот цитата из вышеупомянутой ссылки:

os.listdir (), который возвращает имена файлов, возникает вопрос: должен ли он вернуть Unicode-версия имен файлов, или должен ли он возвращать 8-битные строки содержащие закодированные версии? os.listdir () сделает оба, в зависимости от того, предоставили ли вы каталог путь в виде 8-битной строки или Unicode строка. Если вы передаете строку Unicode как путь, имена файлов будут декодированы используя кодировку файловой системы и список строк Unicode будет возвращается при прохождении 8-битного пути вернет 8-битные версии имена файлов.

  • И, наконец, print хочет строку ascii, а не unicode, поэтому путь должен быть закодирован в ascii.
3 голосов
/ 31 января 2009

Это похоже на проблему Unicode против ASCII - os.listdir возвращает список строк ASCII.

Редактировать: я пробовал это на Python 3.0, также на XP SP2, и os.listdir просто пропустил имена файлов на иврите вместо того, чтобы перечислять их вообще.

Согласно документам, это означает, что он не смог расшифровать его:

Обратите внимание, что когда os.listdir () возвращает список строк, имена файлов, которые не могут быть должным образом декодированы, скорее опущены чем повышение UnicodeError.

1 голос
/ 31 января 2009

Это работает как шарм, используя Python 2.5.1 на OS X:

subdir/bar.txt True
subdir/foo.txt True
subdir/עִבְרִית.txt True

Может, это как-то связано с Windows XP?

РЕДАКТИРОВАТЬ: я также пытался с Unicode-строки, чтобы попытаться лучше имитировать поведение Windows:

for f in os.listdir(u'subdir'):
  pf = os.path.join(u'subdir', f)
  print pf, os.path.exists(pf)

subdir/bar.txt True
subdir/foo.txt True
subdir/עִבְרִית.txt True

В Терминале (приложение командной строки os x stock). Используя IDLE, он все еще работал, но неправильно печатал имя файла. Чтобы убедиться, что это действительно Unicode, я проверил:

>>>os.listdir(u'listdir')[2]
u'\u05e2\u05b4\u05d1\u05b0\u05e8\u05b4\u05d9\u05ea.txt'
0 голосов
/ 31 января 2009

Знак вопроса - это более или менее универсальный символ, отображаемый, когда символ Юникода не может быть представлен в определенной кодировке. Ваш терминал или интерактивный сеанс под Windows, вероятно, использует ASCII или ISO-8859-1 или что-то еще. Таким образом, фактическая строка - это Unicode, но она переводится в ???? при печати на терминал. Вот почему он работает для PEZ, используя OSX.

...