web-dev-qa-db-fra.com

Python 3: chemins d'accès aux fichiers os.walk () UnicodeEncodeError: le codec 'utf-8' ne peut pas coder: les substituts ne sont pas autorisés

Ce code:

for root, dirs, files in os.walk('.'):
    print(root)

Me donne cette erreur:

UnicodeEncodeError: 'utf-8' codec can't encode character '\udcc3' in position 27: surrogates not allowed

Comment puis-je parcourir un arbre de fichiers sans obtenir des chaînes toxiques comme celle-ci?

13
Collin Anderson

Sous Linux, les noms de fichiers ne sont «qu'un tas d'octets» et ne sont pas nécessairement encodés dans un encodage particulier. Python 3 essaie de tout transformer en chaînes Unicode. Ce faisant, les développeurs ont mis au point un système permettant de traduire les chaînes d'octets en chaînes Unicode et inversement sans perte et sans connaître l'encodage d'origine. Ils ont utilisé des substituts partiels pour coder les «mauvais» octets, mais le codeur UTF8 normal ne peut pas les gérer lors de l'impression sur le terminal.

Par exemple, voici une chaîne d'octets non UTF8:

>>> b'C\xc3N'.decode('utf8','surrogateescape')
'C\udcc3N'

Il peut être converti vers et à partir d'Unicode sans perte:

>>> b'C\xc3N'.decode('utf8','surrogateescape').encode('utf8','surrogateescape')
b'C\xc3N'

Mais cela ne peut pas être imprimé:

>>> 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

Vous devrez déterminer ce que vous voulez faire avec les noms de fichiers avec des encodages autres que ceux par défaut. Peut-être juste les encoder à nouveau en octets originaux et les décoder avec un remplacement inconnu. Utilisez-le pour l'affichage mais conservez le nom d'origine pour accéder au fichier.

>>> b'C\xc3N'.decode('utf8','replace')
C�N

os.walk peut également prendre une chaîne d'octets et renverra des chaînes d'octets au lieu de chaînes Unicode:

for p,d,f in os.walk(b'.'):

Ensuite, vous pouvez décoder comme vous le souhaitez.

23
Mark Tolonen

J'ai fini par passer une chaîne d'octets à os.walk() qui renverra apparemment des chaînes d'octets au lieu de chaînes unicode incorrect

for root, dirs, files in os.walk(b'.'):
    print(root)
5
Collin Anderson

Filtrer avec sed ou grep:

set | sed -n '/^[a-zA-Z0-9_]*=/p'
# ... or ...
set | grep '^[a-zA-Z0-9_]*='
# ... or ...
set | egrep '^[_[:alnum:]]+='

Cela dépend de la folie de vos noms de variables. La dernière version devrait gérer la plupart des choses folles.

0
Walker Hale IV