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

I am attempting to work with a very large dataset that has some non-standard characters in it. I need to use unicode, as per the job specs, but I am baffled. (And quite possibly doing it all wrong.)

I open the CSV using:

 15     ncesReader = csv.reader(open('geocoded_output.csv', 'rb'), delimiter='\t', quotechar='"')

Then, I attempt to encode it with:

name=school_name.encode('utf-8'), street=row[9].encode('utf-8'), city=row[10].encode('utf-8'), state=row[11].encode('utf-8'), zip5=row[12], zip4=row[13],county=row[25].encode('utf-8'), lat=row[22], lng=row[23])

I'm encoding everything except the lat and lng because those need to be sent out to an API. When I run the program to parse the dataset into what I can use, I get the following Traceback.

Traceback (most recent call last):
File "push_into_db.py", line 80, in <module>
main()
File "push_into_db.py", line 74, in main
district_map = buildDistrictSchoolMap()
File "push_into_db.py", line 32, in buildDistrictSchoolMap
county=row[25].encode('utf-8'), lat=row[22], lng=row[23])
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 in position 2: ordinal not in range(128)

I think I should tell you that I'm using python 2.7.2, and this is part of an app build on django 1.4. I've read several posts on this topic, but none of them seem to directly apply. Any help will be greatly appreciated.

You might also want to know that some of the non-standard characters causing the issue are Ñ and possibly É.

367345 次浏览

Unicode 不等于 UTF-8,后者只是前者的 编码

你做的方式不对。您是 阅读 UTF-8-encoded数据,因此必须将 解码 UTF-8编码的 String 转换为 unicode 字符串。

因此,只需用 .decode替换 .encode,它就应该可以工作(如果. csv 是 UTF-8编码的)。

不过没什么好羞愧的。我敢打赌,5个程序员中就有3个在最初理解这个问题时遇到了困难,如果不是更多的话;)

Update: 如果您的输入数据是 没有UTF-8编码的,那么当然必须使用适当的编码 .decode()。如果没有给定任何内容,python 假定使用 ASCII,这显然会在非 ASCII 字符上失败。

把这几行加到你的代码里:

1. Python 2

import sys
reload(sys)
sys.setdefaultencoding('utf-8')

2. Python 3

import sys
from importlib import reload
reload(sys)
sys.setdefaultencoding('utf-8')

出现错误的主要原因是 python 采用的默认编码是 ASCII。 因此,如果由 encode('utf8')编码的字符串数据包含 ASCII 范围之外的字符,例如对于像‘ hgvcj something something something 387’这样的字符串,python 将抛出错误,因为字符串不是预期的编码格式。

如果您使用的 Python 版本早于3.5版本,可靠的修复方法是将 python 所采用的默认编码设置为 utf8:

import sys
reload(sys)
sys.setdefaultencoding('utf8')
name = school_name.encode('utf8')

这样,python 就能够预测字符串中超出 ASCII 范围的字符。

但是,如果您使用的是 python 3.5或更高版本,reload ()函数不可用,因此必须使用 decode 例如修复它。

name = school_name.decode('utf8').encode('utf8')

对于 Python3用户来说,你可以这样做

with open(csv_name_here, 'r', encoding="utf-8") as f:
#some codes

它也适用于烧瓶:)

对于 Python 3用户:

将编码从“ ascii”改为“ latin1”就可以了。

另外,您可以尝试使用下面的代码片段读取前10000个字节来自动查找编码:

import chardet
with open("dataset_path", 'rb') as rawdata:
result = chardet.detect(rawdata.read(10000))
print(result)

由于 lat 和 long 的原因,用编码 UTF 16打开。

with open(csv_name_here, 'r', encoding="utf-16") as f:

如果在创建或更新证书时运行 certbot 时出现此问题,请使用以下方法

grep -r -P '[^\x00-\x7f]' /etc/apache2 /etc/letsencrypt /etc/nginx

这个命令在一个字符中找到了冒犯字符“”。注释中的 conf 文件。删除它(您可以编辑注释,因为您希望)和重新加载 nginx 后,一切再次工作。

资料来源: https://github.com/certbot/certbot/issues/5236

我的电脑设置错了地点。

我先说的

>>> import locale
>>> locale.getpreferredencoding(False)
'ANSI_X3.4-1968'

locale.getpreferredencoding(False) 如果不提供编码,则为 open()调用的函数。输出应该是 'UTF-8',但在本例中是一些 ASCII 的变体

然后我运行 bash 命令 locale并得到这个输出

$ locale
LANG=
LANGUAGE=
LC_CTYPE="POSIX"
LC_NUMERIC="POSIX"
LC_TIME="POSIX"
LC_COLLATE="POSIX"
LC_MONETARY="POSIX"
LC_MESSAGES="POSIX"
LC_PAPER="POSIX"
LC_NAME="POSIX"
LC_ADDRESS="POSIX"
LC_TELEPHONE="POSIX"
LC_MEASUREMENT="POSIX"
LC_IDENTIFICATION="POSIX"
LC_ALL=

因此,我使用的是默认的 Ubuntu 语言环境,这会导致 Python 以 ASCII 而不是 UTF-8的形式打开文件。我必须从 设定我的位置en_US.UTF-8

sudo apt install locales
sudo locale-gen en_US en_US.UTF-8
sudo dpkg-reconfigure locales

如果不能在整个系统范围内更改语言环境,那么可以像下面这样调用所有 Python 代码:

PYTHONIOENCODING="UTF-8" python3 ./path/to/your/script.py

或者做

export PYTHONIOENCODING="UTF-8"

将它设置到运行它的 shell 中。

如果 Python 中的文本是 Unicode 文本,那么在处理它时,请注意它是 Unicode 文本。

text=u'unicode text'设置为 text='unicode text'

这招对我很管用。

它的工作原理是仅仅将参数‘ rb’read 二进制而不是‘ r’read

在 Docker 容器内处理此问题。 可能的情况(就像对我一样)是,您只需要生成语言环境,不需要做更多的事情:

sudo locale-gen en_US en_US.UTF-8

在某些情况下,这对我来说已经足够了,因为语言环境已经安装和配置好了。如果必须安装 locale 并对其进行配置,请将以下部分添加到 Dockerfile 中:

RUN apt update && apt install locales && \
sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && \
echo 'LANG="en_US.UTF-8"'>/etc/default/locale && \
dpkg-reconfigure --frontend=noninteractive locales && \
update-locale LANG=en_US.UTF-8


ENV LANG en_US.UTF-8
ENV LANGUAGE en_US.UTF-8
ENV LC_ALL en_US.UTF-8

我是这样测试的:

cat <<EOF > /tmp/test.txt
++*=|@#|¼üöäàéàè!´]]¬|¢|¢¬|{ł|¼½{}}
EOF


python3
import pathlib; pathlib.Path("/tmp/test.txt").read_text()

我在使用 Pickle 卸载时遇到了这个问题。 试试看,

data = pickle.load(f,encoding='latin1')