Python 3: os.walk () пути к файлам UnicodeEncodeError: кодек 'utf-8' не может кодировать: суррогаты не разрешены
этот код:
for root, dirs, files in os.walk('.'):
print(root)
дает мне эту ошибку:
UnicodeEncodeError: 'utf-8' codec can't encode character 'udcc3' in position 27: surrogates not allowed
Как пройти через дерево файлов, не получая токсичных строк, как это?
3 ответов
в Linux имена файлов являются "просто кучей байтов" и не обязательно кодируются в определенной кодировке. Python 3 пытается превратить все в строки Unicode. При этом разработчики придумали схему перевода байтовых строк в строки Unicode и обратно без потерь и без знания исходной кодировки. Они использовали частичные суррогаты для кодирования "плохих" байтов, но обычный кодировщик UTF8 не может обрабатывать их при печати на терминал.
например, вот не-UTF8 байтовая строка:
>>> b'C\xc3N'.decode('utf8','surrogateescape')
'C\udcc3N'
он может быть преобразован в и из Unicode без потерь:
>>> b'C\xc3N'.decode('utf8','surrogateescape').encode('utf8','surrogateescape')
b'C\xc3N'
но его нельзя напечатать:
>>> print(b'C\xc3N'.decode('utf8','surrogateescape'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'utf-8' codec can't encode character '\udcc3' in position 1: surrogates not allowed
вам придется выяснить, что вы хотите сделать с именами файлов с кодировками не по умолчанию. Возможно, просто кодирует их обратно в исходные байты и декодирует их с неизвестной заменой. Используйте это для отображения, но сохраните исходное имя для доступа к файлу.
>>> b'C\xc3N'.decode('utf8','replace')
C�N
os.walk
может также принять byte string и вернет байтовые строки вместо строк Unicode:
for p,d,f in os.walk(b'.'):
тогда вы можете декодировать, как вам нравится.
Я закончил тем, что передал строку байта в os.walk()
который, по-видимому, вернет строки байтов вместо неправильных строк unicode
for root, dirs, files in os.walk(b'.'):
print(root)
С sed
или grep
:
set | sed -n '/^[a-zA-Z0-9_]*=/p'
# ... or ...
set | grep '^[a-zA-Z0-9_]*='
# ... or ...
set | egrep '^[_[:alnum:]]+='
это чувствительно к тому, насколько сумасшедшие имена переменных. Последняя версия должна справиться с большинством сумасшедших вещей.