2

トレースバック:

Traceback (most recent call last):
  File "venues.py", line 22, in <module>
    main()
  File "venues.py", line 19, in main
    print_category(category, 0)
  File "venues.py", line 13, in print_category
    print_category(subcategory, ident+1)
  File "venues.py", line 10, in print_category
    print u'%s: %s' % (category['name'].encode('utf-8'), category['id'])
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 3: ordinal not in range(128)

コード:

# -*- coding: utf-8 -*-

# Using https://github.com/marcelcaraciolo/foursquare
import foursquare 

# Prints categories and subcategories
def print_category(category, ident):
    for i in range(0,ident):
        print u'\t',
    print u'%s: %s' % (category['name'].encode('utf-8'), category['id'])

    for subcategory in category.get('categories', []):
        print_category(subcategory, ident+1)

def main():
    client = foursquare.Foursquare(client_id='id',
                                   client_secret='secret')
    for category in client.venues.categories()['categories']:
        print_category(category, 0)

if __name__ == '__main__':
    main()
4

2 に答える 2

2

秘訣は、すべての文字列処理をソースで完全に Unicode に保つことです。入力 (ファイル/パイプ/コンソール) を読み取るときに Unicode にデコードし、出力を書き込むときにエンコードします。が Unicode の場合category['name']は、そのままにしておきます (`.encode('utf8') を削除します)。

また、コメントごとに:

ただし、実行しようとするとエラーが引き続き発生します: pythonvenues.py >categories.txt が、出力がターミナルに送られるときは発生しません: pythonvenues.py

Python は通常、端末のエンコーディングを決定でき、そのエンコーディングに自動的にエンコードします。これが、端末への書き込みが機能する理由です。シェルのリダイレクトを使用してファイルに出力する場合は、環境変数を介して必要な I/O エンコーディングを Python に伝える必要があります。次に例を示します。

set PYTHONIOENCODING=utf8
python venues.py > categories.txt

cp437エンコーディングを使用する米国の Windows コンソールを使用した実際の例。ソースコードは「UTF-8、BOMなし」で保存されています。ソース コードのバイトが UTF-8 であることは指摘しておく価値がありますが、ソース エンコーディングを宣言して Unicode 文字列を使用すると、Python はソースを正しくデコードprintし、デフォルトのエンコーディングを使用して端末に出力を自動的にエンコードできます。

#coding:utf8
import sys
print sys.stdout.encoding
print u'üéâäàåçêëèïîì'

ここで、Python はデフォルトの端末エンコーディングを使用しますが、リダイレクトされると、エンコーディングが何であるかがわからないため、デフォルトは次のようになりasciiます。

C:\>python example.py
cp437
üéâäàåçêëèïîì

C:\>python example.py >out.txt
Traceback (most recent call last):
  File "example.py", line 4, in <module>
    print u'üéâäàåçêëèïîì'
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-12: ordinal not in range(128)

C:\>type out.txt
None

シェルのリダイレクトを使用しているため、シェル変数を使用して Python にどのエンコーディングを使用するかを指示します。

C:\>set PYTHONIOENCODING=cp437

C:\>python example.py >out.txt

C:\>type out.txt
cp437
üéâäàåçêëèïîì

Python に別のエンコーディングを強制的に使用させることもできますが、この場合、端末は を表示する方法を知りませんUTF-8。端末は、次を使用してファイル内のバイトをまだデコードしていますcp437

C:\>set PYTHONIOENCODING=utf8

C:\>python example.py >out.txt

C:\>type out.txt
utf8
üéâäàåçêëèïîì
于 2013-08-18T19:55:58.507 に答える
1

よくわかりませんが、犯人は の先頭の「u」の文字だと思いますu"%s: %s"。これは、印刷したいものがユニコード文字列ではなくバイト文字列であることを前提としています---これは合理的です(*):適切にエンコードされたバイトを出力します。次のように変更されました。

print '%s: %s' % (category['name'].encode('utf-8'), category['id'])

これにより、Unicode 文字列category['name']が UTF-8 バイト文字列に変換され、残りの処理はバイト文字列で行われます。

(*) ある観点では合理的です。もう 1 つの観点は、Unicode 文字列を出力し、それをエンコードする方法を環境に決定させることですが、そうすると、実際には制御できないいくつかの要因に翻弄されます。そのため、ターミナルまたはファイルへの出力に違いが見られます。これらすべての問題を回避するには、バイト文字列を出力するだけです。

于 2013-08-18T08:41:01.220 に答える