PythonでエラーなしにUnicodeをASCIIに変換する


178

私のコードはWebページを削って、それをUnicodeに変換するだけです。

html = urllib.urlopen(link).read()
html.encode("utf8","ignore")
self.response.out.write(html)

しかし、私はUnicodeDecodeError


Traceback (most recent call last):
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/webapp/__init__.py", line 507, in __call__
    handler.get(*groups)
  File "/Users/greg/clounce/main.py", line 55, in get
    html.encode("utf8","ignore")
UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 2818: ordinal not in range(128)

私はそれがHTMLがどこかに間違った形式のUnicodeの試みを含んでいることを意味すると思います。エラーが発生する代わりに、問題の原因となっているコードバイトを削除できますか?


2
重要な文字を破棄するとエラーになると思います!(また、質問はどこにありますか?)
Arafangion

Webページで「ブレークスペースなし」に遭遇した可能性がありますか?c2バイトを前に付ける必要があります。そうしないと、おそらくデコードエラーが発生します。hexutf8.com
jar

回答:


105

2018年の更新:

2018年2月の時点で、などの圧縮の使用gzip非常に一般的になっています(Google、YouTube、Yahoo、Wikipedia、Reddit、Stack Overflow、Stack Exchange Networkサイトなどの大規模なサイトを含む、すべてのWebサイトの約73%が圧縮を使用しています)。
元の回答のようにgzip圧縮された応答で単純なデコードを行うと、次のようなエラーが表示されます。

UnicodeDecodeError: 'utf8'コーデックは位置1のバイト0x8bをデコードできません:予期しないコードバイト

gzpippedレスポンスをデコードするには、次のモジュールを追加する必要があります(Python 3の場合):

import gzip
import io

注: Python 2 StringIOでは、代わりにio

次に、次のようにコンテンツを解析できます。

response = urlopen("https://example.com/gzipped-ressource")
buffer = io.BytesIO(response.read()) # Use StringIO.StringIO(response.read()) in Python 2
gzipped_file = gzip.GzipFile(fileobj=buffer)
decoded = gzipped_file.read()
content = decoded.decode("utf-8") # Replace utf-8 with the source encoding of your requested resource

このコードは応答を読み取り、バイトをバッファーに入れます。次に、gzipモジュールはGZipFile関数を使用してバッファを読み取ります。その後、gzip圧縮されたファイルを再度バイトに読み込み、最後に通常読み取り可能なテキストにデコードできます。

2010年の元の回答:

使用される実際の値を取得できますlinkか?

さらに.encode()、すでにエンコードされたバイト文字列を使おうとすると、通常この問題が発生します。だからあなたは最初にそれをデコードしようとするかもしれません

html = urllib.urlopen(link).read()
unicode_str = html.decode(<source encoding>)
encoded_str = unicode_str.encode("utf8")

例として:

html = '\xa0'
encoded_str = html.encode("utf8")

失敗する

UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 0: ordinal not in range(128)

その間:

html = '\xa0'
decoded_str = html.decode("windows-1252")
encoded_str = decoded_str.encode("utf8")

エラーなしで成功します。「windows-1252」はとして使用したものであることに注意してください。私はシャルデからこれを手に入れました、そしてそれはそれが正しいという0.5の自信を持っていました!(まあ、1文字の長さの文字列で与えられたように、あなたは何を期待していますか)それを、返されたバイト文字列のエンコーディングに、.urlopen().read()取得したコンテンツに適用されるものに変更する必要があります。

もう1つの問題は、.encode()stringメソッドが変更された文字列を返し、ソースを適切に変更しないことです。したがってself.response.out.write(html)、htmlはhtml.encodeからのエンコードされた文字列ではないので、ある意味では意味がありません(それが最初に目的としていた場合)。

Ignacioが示唆したように、から返された文字列の実際のエンコーディングについては、ソースWebページを確認してくださいread()。メタタグの1つ、または応答のContentTypeヘッダーにあります。それをのパラメーターとして使用します.decode()

ただし、ヘッダーやメタ文字セットの宣言が実際のコンテンツと一致することを確認する責任は他の開発者にあるとは限りません。(これはPITAです。ええ、知っておくべきですが、私以前の1人でした)。


1
あなたの例では、最終行が encoded_str = decoded_str.encode("utf8")
Ajith Antony、

1
Python 2.7.15で試しましたが、このメッセージが表示されましたraise IOError, 'Not a gzipped file'。私がした誤りは何ですか?
ヒョン・グニョンキム

222
>>> u'aあä'.encode('ascii', 'ignore')
'a'

返された文字列をmeta、応答内の適切なタグまたはContent-Typeヘッダーの文字セットを使用してデコードし、エンコードします。

このメソッドencode(encoding, errors)は、エラーのカスタムハンドラーを受け入れます。以外のデフォルト値ignoreは次のとおりです。

>>> u'aあä'.encode('ascii', 'replace')
b'a??'
>>> u'aあä'.encode('ascii', 'xmlcharrefreplace')
b'a&#12354;&#228;'
>>> u'aあä'.encode('ascii', 'backslashreplace')
b'a\\u3042\\xe4'

https://docs.python.org/3/library/stdtypes.html#str.encodeを参照してください


119

イグナシオバスケスエイブラムスの回答の拡張として

>>> u'aあä'.encode('ascii', 'ignore')
'a'

文字からアクセントを取り除き、基本フォームを印刷することが望ましい場合があります。これは

>>> import unicodedata
>>> unicodedata.normalize('NFKD', u'aあä').encode('ascii', 'ignore')
'aa'

また、他の文字(句読点など)を対応する最も近い文字に変換することもできます。たとえば、RIGHT SINGLE QUOTATION MARKユニコード文字は、エンコード時にASCIIアポストロフィに変換されません。

>>> print u'\u2019'

>>> unicodedata.name(u'\u2019')
'RIGHT SINGLE QUOTATION MARK'
>>> u'\u2019'.encode('ascii', 'ignore')
''
# Note we get an empty string back
>>> u'\u2019'.replace(u'\u2019', u'\'').encode('ascii', 'ignore')
"'"

これを達成するためのより効率的な方法がありますが。詳細については、この質問を参照してください。Pythonの「このUnicodeに最適なASCII」データベースどこにありますか?


4
どちらも、尋ねられた質問への対処に役立ち、尋ねられた質問の根底にある可能性のある問題への対処に実用的です。これは、この種の質問に対するモデルの回答です。
shanusmagnus 2013

96

unidecodeを使用してください。奇妙な文字を即座にASCIIに変換し、中国語を音声ASCIIに変換します。

$ pip install unidecode

次に:

>>> from unidecode import unidecode
>>> unidecode(u'北京')
'Bei Jing'
>>> unidecode(u'Škoda')
'Skoda'

3
Halle-freakin-lujah-それは私のために働いた答えを見つけた頃です
Aurielle Perlmann

10
楽しい価値のために賛成。これはすべての強調された言語の単語を壊すことに注意してください。シュコダはシュコダではありません。シュコダはおそらくウナギとホバークラフトで全体を意味します。
シルヴァン

1
私はこれまで何日もインターネットを精査してきました...ありがとう、ありがとうございました
Stephen

23

私はすべてのプロジェクトでこのヘルパー関数を使用しています。Unicodeを変換できない場合は無視します。これはdjangoライブラリに関連付けられていますが、少しの調査でそれをバイパスできます。

from django.utils import encoding

def convert_unicode_to_string(x):
    """
    >>> convert_unicode_to_string(u'ni\xf1era')
    'niera'
    """
    return encoding.smart_str(x, encoding='ascii', errors='ignore')

これを使用した後、Unicodeエラーは発生しなくなりました。


10
それは問題の抑制であり、診断と修正ではありません。「足を切り落とした後は、トウモロコシやバニオンに問題がなくなった」と言っているようなものです。
John Machin

10
私はそれが問題を抑制していることに同意します。でもそれが問題のようです。彼のメモを見てください。「エラーが発生するのではなく、問題の原因となっているコードバイトを削除できますか?」
Gattster

3
これは、単に "some-string" .encode( 'ascii'、 'ignore')を呼び出すのとまったく同じです
Joshua Burns

17
私がSOについて質問して、これらすべての説教の反応を得るのにどれほど疲れているか、あなたに言うことはできません。「私の車は始動しません。」「なぜあなたは車を始動したいのですか?代わりに歩くべきです。」やめて!
shanusmagnus 2013

8
@JohnMachin誰も気にしない。私がRSSフィードに何が遅れたがらくたを入れたかは気にしません、それがASCIIにないいくつかの文字である場合、切り捨てることができます。彼らの問題。私はpythonが実際にそれを抑制し、それに対処することを望み、 'ignore'を指定するたびにエラーを出さないようにします。誰がそのたわごとを思いついたのですか?
user1244215

10

のような壊れたコンソールcmd.exeやHTML出力の場合は、いつでも使用できます。

my_unicode_string.encode('ascii','xmlcharrefreplace')

これにより、すべての非ASCII文字が保持され、純粋なASCII および HTMLで印刷可能になります。

警告本番用コードでこれを使用してエラーを回避する場合は、コードに問題がある可能性があります。これの唯一の有効な使用例は、非Unicodeコンソールへの出力、またはHTMLコンテキストでのHTMLエンティティへの簡単な変換です。

最後に、Windowsでcmd.exeを使用している場合は、入力chcp 65001してutf-8出力を有効にすることができます(Lucida Consoleフォントで動作します)。追加する必要があるかもしれませんmyUnicodeString.encode('utf8')


6

あなたは「」と書いたのですが、HTMLのどこかに間違った形式のユニコードの試みが含まれていると思います。

HTMLには、整形式であるかどうかにかかわらず、あらゆる種類の「Unicodeでの試行」が含まれることは想定されていません。必要に応じて、何らかのエンコードでエンコードされたUnicode文字を含める必要があります。これは通常、最初に提供されます...「charset」を探します。

あなたは文字セットがUTF-8であると仮定しているように見えます...どのような理由で?エラーメッセージに表示される「\ xA0」バイトは、cp1252などのシングルバイト文字セットを使用している可能性があることを示しています。

HTMLの最初の宣言で意味がわからない場合は、chardetを使用して、エンコーディングの可能性を調べてください。

質問に「正規表現」のタグを付けたのはなぜですか?

質問全体を非質問に置き換えた後で更新します。

html = urllib.urlopen(link).read()
# html refers to a str object. To get unicode, you need to find out
# how it is encoded, and decode it.

html.encode("utf8","ignore")
# problem 1: will fail because html is a str object;
# encode works on unicode objects so Python tries to decode it using 
# 'ascii' and fails
# problem 2: even if it worked, the result will be ignored; it doesn't 
# update html in situ, it returns a function result.
# problem 3: "ignore" with UTF-n: any valid unicode object 
# should be encodable in UTF-n; error implies end of the world,
# don't try to ignore it. Don't just whack in "ignore" willy-nilly,
# put it in only with a comment explaining your very cogent reasons for doing so.
# "ignore" with most other encodings: error implies that you are mistaken
# in your choice of encoding -- same advice as for UTF-n :-)
# "ignore" with decode latin1 aka iso-8859-1: error implies end of the world.
# Irrespective of error or not, you are probably mistaken
# (needing e.g. cp1252 or even cp850 instead) ;-)

4

文字列がある場合は、文字列line.encode([encoding], [errors='strict'])メソッドを使用してエンコードタイプを変換できます。

line = 'my big string'

line.encode('ascii', 'ignore')

PythonでのASCIIおよびUnicodeの処理の詳細については、https//docs.python.org/2/howto/unicode.htmlが非常に役立つサイトです


1
文字列にüのような非ASCII文字がある場合、これは機能しません。
sajid 2017

4

答えはあると思いますが、断片的なものしかありません。そのため、次のような問題をすばやく修正することは困難です。

UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 2818: ordinal not in range(128)

例を挙げましょう。次の形式のデータを含むファイルがあるとします(ASCII文字と非ASCII文字を含む)。

1/10 / 17、21:36-土地:ようこそ��

そして、アスキー文字だけを無視して保存したいと考えています。

このコードは次のことを行います:

import unicodedata
fp  = open(<FILENAME>)
for line in fp:
    rline = line.strip()
    rline = unicode(rline, "utf-8")
    rline = unicodedata.normalize('NFKD', rline).encode('ascii','ignore')
    if len(rline) != 0:
        print rline

そしてタイプ(rline)はあなたに与えるでしょう

>type(rline) 
<type 'str'>

これは(標準化されていない)「拡張ASCII」の場合にも機能します
Oliver Zendel '18

1
unicodestring = '\xa0'

decoded_str = unicodestring.decode("windows-1252")
encoded_str = decoded_str.encode('ascii', 'ignore')

私のために働く


-5

Python 2.xを使用しているようです。Python 2.xのデフォルトはasciiで、Unicodeは認識されていません。したがって例外です。

下の行をシバンの後に貼り付けるだけで動作します

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

codingコメントは魔法の万能薬ではありません。エラーが発生している理由を知る必要があります。これは、Pythonソースに不正な文字がある場合にのみ修正されます。これはこの質問には当てはまらないようです。
Mark Ransom
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.