web-dev-qa-db-ja.com

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

このような有毒な文字列を取得せずにファイルツリーをどのようにたどりますか?

15
Collin Anderson

Linuxでは、ファイル名は「単なるバイト」であり、必ずしも特定のエンコーディングでエンコードされているわけではありません。 Python 3はすべてをUnicode文字列に変換しようとします。そうすることで、開発者はバイト文字列をUnicode文字列に変換し、元のエンコーディングを知らずに損失することなく元に戻すスキームを考え出しました。 「不良」バイトをエンコードする部分的なサロゲートですが、通常のUTF8エンコーダーは端末への印刷時にそれらを処理できません。

たとえば、次は非UTF8バイト文字列です。

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

ユニコードとの間で損失なく変換できます:

>>> 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は、バイト文字列を取ることもでき、Unicode文字列の代わりにバイト文字列を返します。

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

その後、好きなようにデコードできます。

27
Mark Tolonen

私はバイト文字列をos.walk()に渡すことになりました。

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

sedまたはgrepでフィルターする:

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

これは、変数名がどれほど狂っているかに敏感です。最後のバージョンはほとんどのクレイジーなものを処理するはずです。

0
Walker Hale IV