web-dev-qa-db-ja.com

python 2および3のUTF-8文字列

次のコードはPython 3:

_people = [u'Nicholas Gyeney', u'Andr\xe9']
writers = ", ".join(people)
print(writers)
print("Writers: {}".format(writers))
_

そして、次の出力を生成します。

_Nicholas Gyeney, André  
Writers: Nicholas Gyeney, André
_

ただし、Python 2.7では、次のエラーが発生します。

_Traceback (most recent call last):
  File "python", line 4, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' 
in position 21: ordinal not in range(128)
_

", ".join(people)", ".join(people).encode('utf-8')に変更することでこのエラーを修正できますが、そうすると、Python 3の出力は次のようになります。

_b'Nicholas Gyeney, Andr\xc3\xa9'  
Writers: b'Nicholas Gyeney, Andr\xc3\xa9'
_

だから私は次のコードを使おうとしました:

_if sys.version_info < (3, 0):
    reload(sys)
    sys.setdefaultencoding('utf-8')

people = [u'Nicholas Gyeney', u'Andr\xe9']
writers = ", ".join(people)
print(writers)
print("Writers: {}".format(writers))
_

これにより、私のコードはすべてのバージョンのPythonで機能します。しかし、私はsetdefaultencoding推奨されていません を使用してそれを読みました。

この問題に対処するための最良のアプローチは何ですか?

5
Meysam

まず、Python 2.7および3.5バージョンをサポートすることを想定しています(2.6および3.0から3.2は少し異なる方法で処理されます)。

すでに読んだように、setdefaultencodingは推奨されておらず、実際には必要ありません。

Unicodeテキストを処理するクロスプラットフォームコードを作成するには、通常、いくつかの場所で文字列エンコーディングを指定するだけで済みます。

  1. スクリプトの上部、Shebangの下に_# -*- coding: utf-8 -*-_があります(コードにUnicodeテキストを含む文字列リテラルがある場合のみ)
  2. 入力データを読み取るとき(テキストファイルやデータベースなどから)
  3. データを出力するとき(ここでもテキストファイルまたはデータベースから)
  4. コードで文字列リテラルを定義する場合

これらのルールに従って、例を変更した方法は次のとおりです。

_#!/usr/bin/env python
# -*- coding: utf-8 -*-

people = ['Nicholas Gyeney', 'André']
writers = ", ".join(people)
print(writers)
print("Writers: {}".format(writers))

print(type(writers))
print(len(writers))
_

出力:

_<type 'str'>
23
_

変更点は次のとおりです。

  • ファイルの先頭に指定されたファイルエンコーディング
  • _\xe9_を実際のUnicode文字に置き換えました(_é_)
  • uプレフィックスを削除しました

Python2.7.12および3.5.2でうまく機能します。

ただし、uプレフィックスを削除すると、pythonはstrではなく通常のunicode型を使用することに注意してください(print(type(writers))の出力を参照)。 )。 _utf-8_の場合、ほとんどの場所でUnicode文字列のように機能しますが、テキストの長さをチェックすると、間違った値が返されます。この例では、lenは_23_を返します。実際の文字数は_22_です。これは、基になる型がstrであり、各バイトを文字としてカウントするためですが、文字_é_は実際には2バイトである必要があります。

言い換えれば、これは(あなたの例のように)データをうまく出力するときに機能しますが、テキストに対して文字列操作をしたい場合には機能しません。この場合でも、文字列を操作する前に、uプレフィックスを使用するか、データを明示的にUnicodeタイプに変換する必要があります。

したがって、単純な例ではない場合でも、uプレフィックスを使用することをお勧めします。あなたは2つの場所でそれを必要とします:

_#!/usr/bin/env python
# -*- coding: utf-8 -*-

people = [u'Nicholas Gyeney', u'André']
writers = ", ".join(people)
print(writers)
print(u"Writers: {}".format(writers))

print(type(writers))
print(len(writers))
_

出力:

_<type 'unicode'>
22
_

注:uプレフィックスはPython 3.0で削除され、下位互換性のためにPython 3.3で再導入されました。

Python 2でのUnicodeテキストの操作のすべての複雑さの詳細な説明は、公式ドキュメントで入手できます: Python 2-Unicode HOWTO

ファイルエンコーディングを指定する特別なコメントの抜粋を次に示します。

Pythonは、任意のエンコーディングでのUnicodeリテラルの記述をサポートしていますが、使用されているエンコーディングを宣言する必要があります。これは、ソースファイルの1行目または2行目に特別なコメントを含めることによって行われます。

_#!/usr/bin/env python
# -*- coding: latin-1 -*-

u = u'abcdé' print ord(u[-1])
_

構文は、ファイルのローカル変数を指定するためのEmacsの表記法に触発されています。 Emacsは多くの異なる変数をサポートしていますが、Pythonはcodingのみをサポートしています。 _-*-_記号は、コメントが特別であることをEmacsに示します。 Pythonには意味がありませんが、慣例です。 Pythonはコメントで_coding: name_または_coding=name_を探します。

このようなコメントを含めない場合、使用されるデフォルトのエンコーディングはASCIIになります。

Learning Python、5th Edition "」という本を手に入れたら、パートVIIIの第37章「Unicodeとバイト文字列」を読むことをお勧めします。高度なトピック。両方の世代のPythonでUnicodeテキストを操作するための詳細な説明が含まれています。

言及する価値のあるもう1つの詳細は、引数がformatにあるかどうかに関係なく、フォーマット文字列がasciiの場合、asciiは常にunicode文字列を返すことです。

それとは逆に、_%_を使用した古いスタイルのフォーマットでは、引数のいずれかがunicodeの場合、unicode文字列が返されます。だからこれを書く代わりに

_print(u"Writers: {}".format(writers))
_

これを書くことができます。これは短くてきれいであるだけでなく、Python 2と3の両方で機能します:

_print("Writers: %s" % writers)
_
9
quasoft

フォーマット時にUnicodeプレフィックスを指定できます。

print(u"Writers: {}".format(writers))

これで問題は解決しますが、Python 3スクリプトに不要なu''プレフィックスが付いています。

バージョンを確認した後でfrom __future__ import unicode_literalsすることもできますが、私はそうしません。u''プレフィックスが十分に機能するため、一般的に操作が難しく、非推奨と見なされています。

Python2では、joinprintにUnicode文字列を使用する必要があります。

people = [u'Nicholas Gyeney', u'Andr\xe9']
writers = u", ".join(people)
print(writers)
print(u"Writers: {}".format(writers))
2
Fomalhaut

答えは、すべてをユニコードにすることです。

# -*- coding: utf-8 -*-
people = [u'Nicholas Gyeney', u'André']
writers = u", ".join(people)
print(writers)
print(u"Writers: {}".format(writers))
0
Stephen Rauch