【问题标题】:UnicodeEncodeError: 'ascii' codec can't encode character in print functionUnicodeEncodeError:“ascii”编解码器无法在打印函数中编码字符
【发布时间】:2019-06-27 23:21:18
【问题描述】:

我的公司正在使用一个数据库,我正在编写一个与该数据库交互的脚本。已经有一个脚本用于将查询放到数据库中,并且该脚本将根据查询从数据库返回结果。

我正在使用 unix 环境,我在我的脚本中使用该脚本从数据库中获取一些数据,并且我正在将查询的结果重定向到一个文件。现在,当我尝试读取此文件时,我收到一条错误消息-

UnicodeEncodeError: 'ascii' codec can't encode character '\u2013' in position 9741: ordinal not in range(128)

我知道由于文件的编码,python 无法读取文件。文件的编码不是 ascii,这就是错误出现的原因。我尝试检查文件的编码并尝试使用自己的编码读取文件。

我使用的代码是-

 os.system("Query.pl \"select title from bug where (ste='KGF-A' AND ( status = 'Not_Approved')) \">patchlet.txt")
 encoding_dict3={}
 encoding_dict3=chardet.detect(open("patchlet.txt", "rb").read())
 print(encoding_dict3)
# Open the patchlet.txt file for storing the last part of titles for latest ACF in a list
 with codecs.open("patchlet.txt",encoding='{}'.format(encoding_dict3['encoding'])) as csvFile
readCSV = csv.reader(csvFile,delimiter=":")
    for row in readCSV:
        if len(row)!=0:
            if len(row) > 1:
                j=len(row)-1
                patchlets_in_latest.append(row[j])
            elif len(row) ==1:
                patchlets_in_latest.append(row[0])               
patchlets_in_latest_list=[]
# calling the strip_list_noempty function for removing newline and whitespace characters
patchlets_in_latest_list=strip_list_noempty(patchlets_in_latest)
# coverting list of titles in set to remove any duplicate entry if present
patchlets_in_latest_set= set(patchlets_in_latest_list)
# Finding duplicate entries in  list
duplicates_in_latest=[k for k,v in Counter(patchlets_in_latest_list).items() if v>1]
# Printing imp info for logs
    print("list of titles of patchlets in latest list are : ")
for i in patchlets_in_latest_list:
   **print(str(i))**
print("No of patchlets in latest list are : {}".format(str(len(patchlets_in_latest_list))))

Query.pl 是 perl 脚本,用于从数据库中获取查询结果。我为“patchlet.txt”(用于存储 HSD 结果的文件)获取的编码是:

{'encoding': 'Windows-1252', 'confidence': 0.73, 'language': ''}

即使我为读取文件提供了相同的编码,我也会收到错误。

请帮我解决这个错误。

编辑: 我正在使用python3.6

EDIT2:

在输出结果时出现错误,文件中有一行包含一些未知字符。该行看起来像:

由于某些故障导致 vtrace 无法与某些跟踪一起使用。

我正在使用 gvim,在 gvim 中,“vtrace”看起来像“~Vvtrace”。然后我在数据库中手动检查了这个字符,这个字符是“-”,根据我的键盘,它既不是连字符也不是下划线。这些字符造成了问题。

我也在linux环境下工作。

编辑 3: 我添加了更多代码来帮助跟踪错误。此外,我还突出显示了一个“打印”语句 (print(str(i))) 我收到错误。

【问题讨论】:

  • encoding='windows-1252'(注意小写'w')或encoding='cp1252'应该可以工作 - 请参阅codec names and aliases
  • 不,两者都不起作用,仍然出现相同的错误-@snakecharmerb
  • 你能分享一个minimal reproducible example,让我们知道你正在运行哪个版本的python?还有追溯?
  • 我猜问题是在您输出结果时发生的,而不是在读取输入时发生的。但是,如果没有一些重现问题的代码和数据,或者至少是代码和回溯,就只能猜测。
  • 再次,回溯来自您未显示的代码。 with codecs.open 之后的某些东西可能只是试图将 print 放到 Python 无法确定正确编码的地方。

标签: python python-3.x character-encoding ascii


【解决方案1】:

问题

根据问题中的信息,程序正在处理非ASCII输入数据,但无法输出非ASCII数据。

具体来说,这段代码:

for i in patchlets_in_latest_list:
   print(str(i))

导致此异常:

UnicodeEncodeError:“ascii”编解码器无法编码字符“\u2013”​​

这种行为在 Python2 中很常见,在 unicode 对象上调用 str 会导致 Python 尝试将对象编码为 ASCII,如果对象包含非 ASCII 字符,则会导致 UnicodeEncodeError

在 Python3 中,在 str 实例上调用 str 不会触发任何编码。然而,在str 上调用print 函数会将str 编码为sys.stdout.encodingsys.stdout.encoding 默认为 locale.getpreferredencoding 返回的值。这通常是您的 linux 用户的 LANG 环境变量。

解决方案

如果我们假设您的程序没有覆盖正常的编码行为,则应通过确保代码由 UTF-8 语言环境中的 Python3 解释器执行来解决问题。

  • 100%确定代码正在由 Python3 解释器执行 - 从程序中打印sys.version_info
  • 在运行脚本时尝试设置PYTHONIOENCODING 环境变量:PYTHONIOENCODING=UTF-8 python3 myscript.py
  • 使用终端中的locale 命令(或echo $LANG)检查您的语言环境。如果它没有以UTF-8 结尾,请考虑更改它。如果您使用的是公司计算机,请咨询您的系统管理员。
  • 如果您的代码在 cron 作业中运行,请记住 cron 作业通常使用“C”或“POSIX”语言环境运行 - 可能使用 ASCII 编码 - 除非明确设置了语言环境。同样,如果脚本在其他用户下运行,请检查他们的区域设置。

解决方法

如果更改环境不可行,您可以在 Python 中解决该问题,方法是使用错误处理程序编码为 ASCII,然后解码回str

在您的特定情况下,有四个有用的错误处理程序,它们的效果通过以下代码演示:

>>> s = 'Hello \u2013 World'
>>> s
'Hello – World'
>>> handlers = ['ignore', 'replace', 'xmlcharrefreplace', 'namereplace']
>>> print(str(s))
Hello – World
>>> for h in handlers:
...     print(f'Handler: {h}:', s.encode('ascii', errors=h).decode('ascii'))
... 
Handler: ignore: Hello  World
Handler: replace: Hello ? World
Handler: xmlcharrefreplace: Hello – World
Handler: namereplace: Hello \N{EN DASH} World

ignorereplace 处理程序会丢失信息 - 您无法判断哪个字符已被空格或问号替换。

xmlcharrefreplacenamereplace 处理程序不会丢失信息,但替换序列可能会降低人类对文本的可读性。

由您决定程序输出的使用者可以接受哪种权衡。

如果您决定使用 replace 处理程序,您可以像这样更改代码:

for i in patchlets_in_latest_list:
    replaced = i.encode('ascii', errors='replace').decode('ascii')
    print(replaced)

无论您在何处打印可能包含非 ASCII 字符的数据。

【讨论】:

  • 嗨....非常感谢您提供如此惊人的解释性答案。它已经完全解决了这个问题......非常感谢 - @snakecharmerb
  • 谢谢!!!这篇文章的更多关键字:Docker Python Ubuntu,“print() 在 iPython 中无法正常工作”
  • 我不知道 cron 作业和服务是否以相同的方式工作。在我的情况下,我想要的只是打印一本字典,我必须使用json.dumps 进行转换,否则会尝试 ascii。不管怎样,谢谢你的回答
猜你喜欢
  • 2015-10-21
  • 2010-12-11
  • 2012-07-02
  • 2010-12-11
  • 2021-09-28
  • 2017-02-01
相关资源
最近更新 更多