尝试在 Python 脚本中使用非 ASCII 文本时出现“SyntaxError:非 ASCII 字符 ...”或“SyntaxError:以 ... 开头的非 UTF-8 代码”
- 2024-12-05 08:38:00
- admin 原创
- 164
问题描述:
我在 Python 2 中尝试过这个代码:
def NewFunction():
return '£'
但我收到一条错误消息:
SyntaxError: Non-ASCII character 'xa3' in file '...' but no encoding declared;
see http://www.python.org/peps/pep-0263.html for details
类似地,在 Python 3 中,如果我编写相同的代码并使用 Latin-1 编码保存,我会得到:
SyntaxError: Non-UTF-8 code starting with 'xa3' in file ... on line 2, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details
如何在代码中的字符串文字中使用井号?
另请参阅:定义 Python 源代码编码的正确方法,了解有关是否需要编码声明以及应如何编写的详细信息。请使用该问题关闭有关如何编写声明的重复问题,并使用这个问题关闭有关解决错误的问题。
解决方案 1:
我建议你阅读错误提示的 PEP。问题是你的代码试图使用 ASCII 编码,但磅号不是 ASCII 字符。尝试使用 UTF-8 编码。你可以从# -*- coding: utf-8 -*-
.py 文件顶部开始。为了更高级,你还可以在代码中逐个字符串定义编码。但是,如果你试图将磅号文字放入代码中,则需要一种支持整个文件的编码。
解决方案 2:
在我的 .py 脚本顶部添加以下两行对我有用(第一行是必要的):
#!/usr/bin/env python
# -*- coding: utf-8 -*-
解决方案 3:
首先将该# -*- coding: utf-8 -*-
行添加到文件开头,然后将其u'foo'
用于所有非 ASCII unicode 数据:
def NewFunction():
return u'£'
或者使用 Python 2.6 以来可用的魔法来使其自动化:
from __future__ import unicode_literals
解决方案 4:
错误信息会告诉你具体哪里出了问题。Python 解释器需要知道非 ASCII 字符的编码。
如果你想返回U+00A3,那么你可以说
return u'/u00a3'
它通过 Unicode 转义序列以纯 ASCII 表示此字符。如果你想返回一个包含文字字节 0xA3 的字节字符串,那就是
return b'xa3'
(其中在 Python 2 中b
是隐式的;但是显式比隐式更好)。
错误消息中链接的 PEP 会指导您如何告诉 Python“此文件不是纯 ASCII;这是我正在使用的编码”。如果编码是 UTF-8,则
# coding=utf-8
或 Emacs 兼容的
# -*- encoding: utf-8 -*-
如果你不知道你的编辑器使用哪种编码来保存此文件,请使用十六进制编辑器之类的工具和谷歌搜索来检查它。 Stack Overflow字符编码标签有一个标签信息页面,其中包含更多信息和一些故障排除提示。
简而言之,在 7 位 ASCII 范围(0x00-0x7F)之外,Python 无法也不应该猜测字节序列代表什么字符串。https: //tripleee.github.io/8bit#a3显示了字节 0xA3 的 21 种可能解释,这仅来自传统的 8 位编码;但它也可能是多字节编码的第一个字节。但事实上,我猜你实际上使用的是 Latin-1,所以你应该有
# coding: latin-1
作为源文件的第一行或第二行。无论如何,如果不知道该字节应该代表哪个字符,人类也无法猜出这一点。
需要注意的是:coding: latin-1
肯定会删除错误消息(因为此编码中不存在技术上不允许的字节序列),但如果实际编码是其他编码,则在解释代码时可能会产生完全错误的结果。声明编码时,您确实必须完全确定文件的编码。
解决方案 5:
在脚本中添加以下两行可以解决我的问题。
# !/usr/bin/python
# coding=utf-8
希望有帮助!
解决方案 6:
您可能正在尝试使用 Python 2 解释器运行 Python 3 文件。目前(截至 2019 年),python
在 Windows 和大多数 Linux 发行版上,当两个版本都安装时,命令默认为 Python 2。
但是如果您确实在处理 Python 2 脚本,那么本页面尚未提及的解决方案是以 UTF-8+BOM 编码重新保存文件,这会在文件开头添加三个特殊字节,它们将明确地告知 Python 解释器(和您的文本编辑器)有关文件编码的信息。
解决方案 7:
概括
如果出现此错误,请使用编码声明来告诉 Python 源代码 (.py) 文件的编码。如果没有这样的声明,Python 3.x 将默认为 UTF-8;Python 2.x 将默认为 ASCII。声明看起来像一条注释,其中包含一个标签coding:
,后跟有效文本编码的名称。所有 ASCII 透明编码均受支持。
例如:
#!/usr/bin/env python
# coding: latin-1
确保文件实际使用的编码,以便编写正确的编码声明。请参阅如何确定文本的编码以获取一些提示。或者,通过检查文本编辑器中的配置选项尝试使用不同的编码。
问题
计算机上的每个文件都是由原始字节组成的,即使文件以“文本模式”打开,这些字节本身也不是“文本” 。当文件应该表示文本时(例如 Python 程序的源代码),需要根据编码规则对其进行解释才能理解数据。
但是,没有明显的方法可以从文件外部指示 Python 源文件的编码 - 例如,import
语法没有提供任何地方来编写编码名称(毕竟,它不一定从源文件导入)。因此,必须以某种方式由文件内容本身描述编码,并且 Python 需要一种方法来动态确定该编码。
为了以一致且可靠的方式完成这项工作,自 2.3 版起,Python 使用一个简单的引导过程来确定文件编码。该过程由 PEP 263描述:
首先,Python 开始读取文件的原始字节。如果它以UTF-8 编码的字节顺序标记(字节
0xEF 0xBB 0xBF
)开头,则 Python 会丢弃这些字节并指出文件的其余部分应为 UTF-8。(以这种方式编写的文件有时被称为“utf-8-sig”编码。)仍会遵循其余过程,以检查是否存在不兼容的编码声明。接下来,Python 尝试使用默认编码(或 UTF-8,如果看到字节顺序标记)和通用换行符读取文件的接下来两行:
+ 如果第一行不是注释(请注意,shebang行在 Python 语法中也是注释),则对文件的其余部分使用默认编码。
+ 否则,如果第一行是*编码声明*(与特定正则表达式匹配的注释),则使用为文件其余部分声明的编码。
+ 否则,如果第二行是编码声明,则使用为文件其余部分声明的编码。
+ 否则,对文件的其余部分使用默认编码。
如果文件以 UTF-8 字节顺序标记开头,并且发现除 UTF-8 之外的编码声明,则会引发异常。
Python 使用以下正则表达式检测编码声明:
^[ ]*#.*?coding[:=][ ]*([-_.a-zA-Z0-9]+)
这是故意允许的;它旨在匹配其他工具(例如 Vim 和 Emacs 文本编辑器)已经在使用的几个标准编码声明。
编码声明的语法也经过设计,因此只需要 ASCII 中可表示的字符。因此,可以使用任何“ASCII 透明”编码。默认编码也是 ASCII 透明的;因此,如果前两行包含编码声明,它将被正确读取,如果没有,则无论如何都会对文件的其余部分使用相同的(默认)编码。最终效果就像始终假设正确的编码一样,即使一开始并不知道它。很聪明,对吧?
但是,请注意,不支持 UTF-16 和其他非 ASCII 透明编码。在此类编码中,无法使用默认编码读取编码声明,因此无法处理。字节顺序标记也不能用于表示 UTF-16:它根本无法识别。似乎最初有计划支持这一点,但后来被放弃了。
Python 3.x
PEP 3120将默认编码更改为UTF-8。因此,源文件可以简单地使用 UTF-8 编码保存,根据 Unicode 标准包含任意文本,并且无需编码声明即可使用。纯 ASCII 数据也是有效的 UTF-8 数据,因此仍然没有问题。
如果必须使用不同的ASCII 透明编码(如 Latin-1 (ISO-8859-1) 或 Shift-JIS)来解释源代码,请使用编码声明。例如:
#!/usr/bin/python
# -*- coding: iso-8859-1 -*-
# Assuming the file is actually encoded in Latin-1,
# the text character here would be represented as a 0xff byte.
# This would not be valid UTF-8 data, so the declaration is necessary.
# or else a SyntaxError will occur.
# In UTF-8, the text would be represented as 0xc3 0xbf.
print('ÿ')
# Similarly, without the encoding declaration, this line would print ÿ instead.
print('ÿ')
Python 2.x
默认编码为ASCII£
。因此,在源文件中写入任何非 ASCII 文本(例如 )时都需要编码声明。
请注意,无论源编码是什么,在 2.x 中使用 Unicode 文本仍需要 Unicode 文字。指定编码可以让 Python 2.x 解释'ÿ'
为有效的源代码(并且为 Latin-1 输入正确指定 Latin-1,而不是 UTF-8,可以让它将该文本视为 而ÿ
不是ÿ
),但这仍然是一个字节文字(不幸的是称为str
)。要创建实际的 Unicode 字符串,请确保使用u
前缀或适当的“未来导入”:from __future__ import unicode_literals
。
(但是,为了使这样的字符串可打印,可能还需要做更多的事情,特别是在 Windows 上;而且还有很多其他事情可能出错。Python 3 自动修复了所有这些问题。对于任何因为不愿意明确指定编码而坚持使用古老的、不受支持的版本的人:请重新考虑。“显式优于隐式”。从长远来看,3.x 的方式更容易、更令人愉快。)
其他解决方法
无论编码如何,Unicode 转义都可用于在字符串文字中包含任意 Unicode 字符:
>>> # With every supported source file encoding, the following is represented
>>> # with the same bytes in the source file, AND prints the same string:
>>> print('xf8/u86c7U0001f9b6')
扫码咨询,免费领取项目管理大礼包!