簡體   English   中英

如何修復:“UnicodeDecodeError:‘ascii’編解碼器無法解碼字節”

[英]How to fix: "UnicodeDecodeError: 'ascii' codec can't decode byte"

as3:~/ngokevin-site# nano content/blog/20140114_test-chinese.mkd
as3:~/ngokevin-site# wok
Traceback (most recent call last):
File "/usr/local/bin/wok", line 4, in
Engine()
File "/usr/local/lib/python2.7/site-packages/wok/engine.py", line 104, in init
self.load_pages()
File "/usr/local/lib/python2.7/site-packages/wok/engine.py", line 238, in load_pages
p = Page.from_file(os.path.join(root, f), self.options, self, renderer)
File "/usr/local/lib/python2.7/site-packages/wok/page.py", line 111, in from_file
page.meta['content'] = page.renderer.render(page.original)
File "/usr/local/lib/python2.7/site-packages/wok/renderers.py", line 46, in render
return markdown(plain, Markdown.plugins)
File "/usr/local/lib/python2.7/site-packages/markdown/init.py", line 419, in markdown
return md.convert(text)
File "/usr/local/lib/python2.7/site-packages/markdown/init.py", line 281, in convert
source = unicode(source)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe8 in position 1: ordinal not in range(128). -- Note: Markdown only accepts unicode input!

如何解決?

在其他一些基於python的static博客應用中,可以成功發布中文帖子。 比如這個應用程序: http://github.com/vrypan/bucket3 在我的站點http://bc3.brite.biz/可以成功發布中文帖子。

tl;博士/快速修復

  • 不要隨意解碼/編碼
  • 不要假設您的字符串是 UTF-8 編碼的
  • 嘗試在您的代碼中盡快將字符串轉換為 Unicode 字符串
  • 修復您的語言環境: 如何解決 Python 3.6 中的 UnicodeDecodeError?
  • 不要試圖使用快速reload技巧

Python 2.x 中的 Unicode Zen - 長版

不看源頭很難知道根本原因,所以我只能籠統地說。

UnicodeDecodeError: 'ascii' codec can't decode byte通常發生在您嘗試將包含非 ASCII 的 Python 2.x str轉換為 Unicode 字符串而不指定原始字符串的編碼時。

簡而言之,Unicode 字符串是一種完全獨立的 Python 字符串類型,不包含任何編碼。 它們只保存 Unicode點代碼,因此可以保存整個范圍內的任何 Unicode 點。 字符串包含編碼文本,如 UTF-8、UTF-16、ISO-8895-1、GBK、Big5 等。字符串被解碼為 Unicode而 Unicode被編碼為字符串 文件和文本數據始終以編碼字符串傳輸。

Markdown 模塊作者可能使用unicode() (拋出異常的地方)作為其余代碼的質量門——它將轉換 ASCII 或將現有的 Unicode 字符串重新包裝為新的 Unicode 字符串。 Markdown 作者無法知道傳入字符串的編碼,因此在傳遞給 Markdown 之前將依賴您將字符串解碼為 Unicode 字符串。

Unicode 字符串可以在您的代碼中使用字符串的u前綴聲明。 例如

>>> my_u = u'my ünicôdé strįng'
>>> type(my_u)
<type 'unicode'>

Unicode 字符串也可能來自文件、數據庫和網絡模塊。 發生這種情況時,您無需擔心編碼。

陷阱

即使您沒有顯式調用unicode()也可能發生從str到 Unicode 的轉換。

以下場景會導致UnicodeDecodeError異常:

# Explicit conversion without encoding
unicode('€')

# New style format string into Unicode string
# Python will try to convert value string to Unicode first
u"The currency is: {}".format('€')

# Old style format string into Unicode string
# Python will try to convert value string to Unicode first
u'The currency is: %s' % '€'

# Append string to Unicode
# Python will try to convert string to Unicode first
u'The currency is: ' + '€'         

例子

在下圖中,您可以看到單詞café是如何根據終端類型以“UTF-8”或“Cp1252”編碼進行編碼的。 在這兩個例子中, caf只是普通的 ascii。 在 UTF-8 中, é使用兩個字節進行編碼。 在“Cp1252”中,é 是 0xE9(這也恰好是 Unicode 點值(這不是巧合))。 調用正確的decode()並成功轉換為 Python Unicode: 字符串轉換為 Python Unicode 字符串的示意圖

在這個圖中, decode()是用ascii調用的(這與調用unicode()沒有給定編碼相同)。 由於 ASCII 不能包含大於0x7F字節,這將引發UnicodeDecodeError異常:

使用錯誤編碼將字符串轉換為 Python Unicode 字符串的示意圖

Unicode 三明治

在您的代碼中形成一個 Unicode 三明治是一種很好的做法,您可以在其中將所有傳入數據解碼為 Unicode 字符串,使用 Unicode,然后在輸出時編碼為str 這使您無需擔心代碼中間的字符串編碼。

輸入/解碼

源代碼

如果您需要將非 ASCII 編碼到您的源代碼中,只需通過在字符串前加上u前綴來創建 Unicode 字符串。 例如

u'Zürich'

為了讓 Python 解碼你的源代碼,你需要添加一個編碼頭來匹配你文件的實際編碼。 例如,如果您的文件被編碼為“UTF-8”,您將使用:

# encoding: utf-8

僅當您的源代碼中有非 ASCII 時才需要這樣做。

文件

通常從文件接收非 ASCII 數據。 io模塊提供了一個 TextWrapper,它使用給定的encoding動態解碼您的文件。 您必須為文件使用正確的編碼 - 它不容易被猜到。 例如,對於 UTF-8 文件:

import io
with io.open("my_utf8_file.txt", "r", encoding="utf-8") as my_file:
     my_unicode_string = my_file.read() 

my_unicode_string然后適合傳遞給 Markdown。 如果read()行中出現UnicodeDecodeError ,那么您可能使用了錯誤的編碼值。

CSV 文件

Python 2.7 CSV 模塊不支持非 ASCII 字符😩。 但是,使用https://pypi.python.org/pypi/backports.csv 可以獲得幫助

像上面一樣使用它,但將打開的文件傳遞給它:

from backports import csv
import io
with io.open("my_utf8_file.txt", "r", encoding="utf-8") as my_file:
    for row in csv.reader(my_file):
        yield row

數據庫

大多數 Python 數據庫驅動程序可以以 Unicode 格式返回數據,但通常需要一些配置。 SQL 查詢始終使用 Unicode 字符串。

MySQL

在連接字符串中添加:

>>> db = MySQLdb.connect(host="localhost", user='root', passwd='passwd', db='sandbox', use_unicode=True, charset="utf8")

例如

psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
psycopg2.extensions.register_type(psycopg2.extensions.UNICODEARRAY)
PostgreSQL

添加:

 psycopg2.extensions.register_type(psycopg2.extensions.UNICODE) psycopg2.extensions.register_type(psycopg2.extensions.UNICODEARRAY)

HTTP

網頁幾乎可以用任何編碼進行編碼。 Content-type標頭應包含一個charset字段以提示編碼。 然后可以根據該值手動解碼內容。 或者, Python-Requestsresponse.text返回 Unicode。

手動

如果您必須手動解碼字符串,您可以簡單地執行my_string.decode(encoding) ,其中encoding是適當的編碼。 此處給出了 Python 2.x 支持的編解碼器: 標准編碼 同樣,如果你得到UnicodeDecodeError那么你可能得到了錯誤的編碼。

三明治的肉

像處理普通字符串一樣使用 Unicode。

輸出

標准輸出/打印

print通過標准輸出流寫入。 Python 嘗試在 stdout 上配置編碼器,以便將 Unicode 編碼為控制台的編碼。 例如,如果 Linux shell 的localeen_GB.UTF-8 ,則輸出將被編碼為UTF-8 在 Windows 上,您將被限制為 8 位代碼頁。

錯誤配置的控制台(例如損壞的區域設置)可能會導致意外的打印錯誤。 PYTHONIOENCODING環境變量可以強制標准輸出的編碼。

文件

就像輸入一樣, io.open可用於透明地將 Unicode 轉換為編碼的字節字符串。

數據庫

相同的讀取配置將允許直接寫入 Unicode。

蟒蛇 3

Python 3 的 Unicode 能力並不比 Python 2.x 多,但它在這個主題上的困惑稍微少一些。 例如,常規str現在是 Unicode 字符串,而舊str現在是bytes

默認編碼是 UTF-8,所以如果你.decode()一個字節字符串而不給出編碼,Python 3 使用 UTF-8 編碼。 這可能解決了人們 50% 的 Unicode 問題。

此外,默認情況下open()在文本模式下運行,因此返回解碼后的str (Unicode str )。 編碼源自您的語言環境,在 Un*x 系統上通常是 UTF-8,或者在 Windows 機器上是 8 位代碼頁,例如 windows-1251。

為什么你不應該使用sys.setdefaultencoding('utf8')

這是一個討厭的 hack(你必須使用reload是有原因的),它只會掩蓋問題並阻礙你遷移到 Python 3.x。 了解問題,解決根本原因並享受 Unicode zen。 請參閱為什么我們不應該在 py 腳本中使用 sys.setdefaultencoding("utf-8")? 欲知更多詳情

最后我明白了:

as3:/usr/local/lib/python2.7/site-packages# cat sitecustomize.py
# encoding=utf8  
import sys  

reload(sys)  
sys.setdefaultencoding('utf8')

讓我檢查一下:

as3:~/ngokevin-site# python
Python 2.7.6 (default, Dec  6 2013, 14:49:02)
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> reload(sys)
<module 'sys' (built-in)>
>>> sys.getdefaultencoding()
'utf8'
>>>

上面顯示了 python 的默認編碼是utf8 那么錯誤就沒有了。

這是經典的“unicode 問題”。 我相信解釋這一點超出了 StackOverflow 答案的范圍,無法完全解釋正在發生的事情。

這很好解釋here

簡而言之,您已將一些被解釋為字節字符串的內容傳遞給需要將其解碼為 Unicode 字符的內容,但默認編解碼器 (ascii) 失敗了。

我向您指出的演示文稿提供了避免這種情況的建議。 使您的代碼成為“unicode 三明治”。 在 Python 2 中,使用from __future__ import unicode_literals幫助。

更新:如何修復代碼:

好的 - 在您的變量“源”中,您有一些字節。 從你的問題中不清楚他們是如何進入那里的——也許你是從網絡表格中讀到的? 在任何情況下,它們都不是用 ascii 編碼的,但假設它們是,python 正試圖將它們轉換為 unicode。 您需要明確地告訴它編碼是什么。 這意味着您需要知道編碼是什么! 這並不總是那么容易,這完全取決於這個字符串的來源。 您可以嘗試一些常見的編碼 - 例如 UTF-8。 你告訴 unicode() 編碼作為第二個參數:

source = unicode(source, 'utf-8')

在某些情況下,當您檢查默認編碼( print sys.getdefaultencoding() )時,它會返回您使用的是 ASCII。 如果更改為 UTF-8,則不起作用,具體取決於變量的內容。 我找到了另一種方法:

import sys
reload(sys)  
sys.setdefaultencoding('Cp1252')

我正在尋找解決以下錯誤消息:

unicodedecodeerror:“ascii”編解碼器無法解碼位置 5454 中的字節 0xe2:序號不在范圍內(128)

我終於通過指定“編碼”來修復它:

f = open('../glove/glove.6B.100d.txt', encoding="utf-8")

也希望能幫到你。

"UnicodeDecodeError: 'ascii' codec can't decode byte"

此錯誤的原因: input_string 必須是 unicode 但給出了 str

"TypeError: Decoding Unicode is not supported"

此錯誤的原因:試圖將 unicode input_string 轉換為 unicode


因此,首先檢查您的 input_string 是否為str並在必要時轉換為 unicode:

if isinstance(input_string, str):
   input_string = unicode(input_string, 'utf-8')

其次,上面只是改變了類型,但沒有刪除非 ascii 字符。 如果要刪除非 ascii 字符:

if isinstance(input_string, str):
   input_string = input_string.decode('ascii', 'ignore').encode('ascii') #note: this removes the character and encodes back to string.

elif isinstance(input_string, unicode):
   input_string = input_string.encode('ascii', 'ignore')

為了在 Ubuntu 安裝中的操作系統級別解決此問題,請檢查以下內容:

$ locale charmap

如果你得到

locale: Cannot set LC_CTYPE to default locale: No such file or directory

代替

UTF-8

然后像這樣設置LC_CTYPELC_ALL

$ export LC_ALL="en_US.UTF-8"
$ export LC_CTYPE="en_US.UTF-8"

我發現最好的方法是始終轉換為 unicode - 但這很難實現,因為在實踐中,您必須檢查每個參數並將其轉換為您編寫的每個函數和方法,其中包括某種形式的字符串處理。

所以我想出了以下方法來保證來自任一輸入的 unicodes 或字節字符串。 簡而言之, 包括並使用以下 lambda:

# guarantee unicode string
_u = lambda t: t.decode('UTF-8', 'replace') if isinstance(t, str) else t
_uu = lambda *tt: tuple(_u(t) for t in tt) 
# guarantee byte string in UTF8 encoding
_u8 = lambda t: t.encode('UTF-8', 'replace') if isinstance(t, unicode) else t
_uu8 = lambda *tt: tuple(_u8(t) for t in tt)

例子:

text='Some string with codes > 127, like Zürich'
utext=u'Some string with codes > 127, like Zürich'
print "==> with _u, _uu"
print _u(text), type(_u(text))
print _u(utext), type(_u(utext))
print _uu(text, utext), type(_uu(text, utext))
print "==> with u8, uu8"
print _u8(text), type(_u8(text))
print _u8(utext), type(_u8(utext))
print _uu8(text, utext), type(_uu8(text, utext))
# with % formatting, always use _u() and _uu()
print "Some unknown input %s" % _u(text)
print "Multiple inputs %s, %s" % _uu(text, text)
# but with string.format be sure to always work with unicode strings
print u"Also works with formats: {}".format(_u(text))
print u"Also works with formats: {},{}".format(*_uu(text, text))
# ... or use _u8 and _uu8, because string.format expects byte strings
print "Also works with formats: {}".format(_u8(text))
print "Also works with formats: {},{}".format(*_uu8(text, text))

這里有一些關於這個的更多推理

有同樣的錯誤,這解決了我的錯誤。 謝謝! python 2 和 python 3 在 unicode 處理方面的不同使得腌制文件與加載非常不兼容。 所以使用 python pickle 的編碼參數。 當我嘗試從 python 3.7 打開腌制數據時,下面的鏈接幫助我解決了類似的問題,而我的文件最初保存在 python 2.x 版本中。 https://blog.modest-destiny.com/posts/python-2-and-3-compatible-pickle-save-and-load/我在我的腳本中復制了 load_pickle 函數並在加載我的腳本時調用了 load_pickle(pickle_file) input_data 像這樣:

input_data = load_pickle("my_dataset.pkl")

load_pickle 函數在這里:

def load_pickle(pickle_file):
    try:
        with open(pickle_file, 'rb') as f:
            pickle_data = pickle.load(f)
    except UnicodeDecodeError as e:
        with open(pickle_file, 'rb') as f:
            pickle_data = pickle.load(f, encoding='latin1')
    except Exception as e:
        print('Unable to load data ', pickle_file, ':', e)
        raise
    return pickle_data

編碼將 unicode 對象轉換為字符串對象。 我認為您正在嘗試對字符串對象進行編碼。 首先將您的結果轉換為 unicode 對象,然后將該 unicode 對象編碼為“utf-8”。 例如

    result = yourFunction()
    result.decode().encode('utf-8')

我有同樣的錯誤,URL 包含非 ascii 字符(值 > 128 的字節),我的解決方案:

url = url.decode('utf8').encode('utf-8')

注意:utf-8、utf8 只是別名。 僅使用 'utf8' 或 'utf-8' 應該以相同的方式工作

就我而言,在 Python 2.7 中對我有用,我想這個賦值改變了str內部表示中的“某些東西”——即,它強制對url支持的字節序列進行正確解碼,最后將字符串放入utf- 8 str ,所有魔法都在正確的地方。 Python 中的 Unicode 對我來說是黑魔法。 希望有用

這對我有用:

    file = open('docs/my_messy_doc.pdf', 'rb')

我遇到了同樣的問題,但它不適用於 Python 3。我遵循了這個,它解決了我的問題:

enc = sys.getdefaultencoding()
file = open(menu, "r", encoding = enc)

您必須在讀取/寫入文件時設置編碼。

簡而言之,要確保在 Python 2 中正確處理 unicode:

  • 使用io.open讀取/寫入文件
  • 使用from __future__ import unicode_literals
  • 配置其他數據輸入/輸出(例如,數據庫、網絡)以使用 unicode
  • 如果您無法將輸出配置為 utf-8,請將您的輸出轉換為它們print(text.encode('ascii', 'replace').decode())

有關解釋,請參閱@Alastair McCormack 的詳細回答

我在字符串“PastelerÃa Mallorca”上遇到了同樣的問題,我用以下方法解決了:

unicode("Pastelería Mallorca", 'latin-1')

在 Django (1.9.10)/Python 2.7.5 項目中,我經常遇到UnicodeDecodeError異常; 主要是當我嘗試將 unicode 字符串提供給日志記錄時。 我為任意對象創建了一個輔助函數,基本上將其格式化為 8 位 ascii 字符串,並將表中沒有的任何字符替換為“?”。 我認為這不是最好的解決方案,但由於默認編碼是 ascii(我不想更改它),它將執行以下操作:

def encode_for_logging(c, encoding='ascii'):
    if isinstance(c, basestring):
        return c.encode(encoding, 'replace')
    elif isinstance(c, Iterable):
        c_ = []
        for v in c:
            c_.append(encode_for_logging(v, encoding))
        return c_
    else:
        return encode_for_logging(unicode(c))
`

當我們的字符串中有一些非 ASCII 字符並且我們在沒有正確解碼的情況下對該字符串執行任何操作時,就會發生此錯誤。 這幫助我解決了我的問題。 我正在讀取一個包含列 ID、文本和解碼字符的 CSV 文件,如下所示:

train_df = pd.read_csv("Example.csv")
train_data = train_df.values
for i in train_data:
    print("ID :" + i[0])
    text = i[1].decode("utf-8",errors="ignore").strip().lower()
    print("Text: " + text)

這是我的解決方案,只需添加編碼即可。 with open(file, encoding='utf8') as f

而且因為讀取glove文件需要很長時間,所以我推薦glove文件轉成numpy文件。 當您在 netx 時間讀取嵌入權重時,它將節省您的時間。

import numpy as np
from tqdm import tqdm


def load_glove(file):
    """Loads GloVe vectors in numpy array.
    Args:
        file (str): a path to a glove file.
    Return:
        dict: a dict of numpy arrays.
    """
    embeddings_index = {}
    with open(file, encoding='utf8') as f:
        for i, line in tqdm(enumerate(f)):
            values = line.split()
            word = ''.join(values[:-300])
            coefs = np.asarray(values[-300:], dtype='float32')
            embeddings_index[word] = coefs

    return embeddings_index

# EMBEDDING_PATH = '../embedding_weights/glove.840B.300d.txt'
EMBEDDING_PATH = 'glove.840B.300d.txt'
embeddings = load_glove(EMBEDDING_PATH)

np.save('glove_embeddings.npy', embeddings) 

要點鏈接: https : //gist.github.com/BrambleXu/634a844cdd3cd04bb2e3ba3c83aef227

在 Python 文件的頂部指定: # encoding= utf-8 ,它應該可以解決問題

我在使用 Python2.7 時遇到了這個錯誤。 我在嘗試運行許多 python 程序時發生了這種情況,但我設法用這個簡單的腳本重現了它:

#!/usr/bin/env python

import subprocess
import sys

result = subprocess.Popen([u'svn', u'info'])
if not callable(getattr(result, "__enter__", None)) and not callable(getattr(result, "__exit__", None)):
    print("foo")
print("bar")

成功后,它應該打印出“foo”和“bar”,如果您不在 svn 文件夾中,則可能會顯示一條錯誤消息。

失敗時,它應該打印'UnicodeDecodeError: 'ascii' codec can't decode byte 0xc4 in position 39: ordinal not in range(128)'

在嘗試重新生成我的語言環境和此問題中發布的許多其他解決方案后,我了解到錯誤的發生是因為我在 PATH 環境變量中編碼了一個特殊字符 (ĺ)。 '~/.bashrc' 中修復 PATH 並退出我的會話並再次輸入后,(顯然采購'~/.bashrc'不起作用),問題就消失了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM