“语法错误:非ASCII字符...”或“语法错误:以...开头的非UTF-8代码”尝试在Python脚本中使用非ASCII文本

zkure5ic  于 2023-03-16  发布在  Python
关注(0)|答案(7)|浏览(204)

我在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

如何在代码中的字符串常量中使用磅号?

vddsk6oq

vddsk6oq1#

我建议阅读错误代码提供的PEP。问题是您的代码尝试使用ASCII编码,但磅符号不是ASCII字符。请尝试使用UTF-8编码。您可以从将# -*- coding: utf-8 -*-放在.py文件的顶部开始。要获得更高级的功能,您还可以在代码中逐个字符串地定义编码。然而,如果你想在代码中加入磅号文字,你需要一个编码来支持整个文件。

4ktjp1zp

4ktjp1zp2#

在我的.py脚本顶部添加以下两行对我来说很有效(第一行是必需的):

#!/usr/bin/env python
# -*- coding: utf-8 -*-
nzk0hqpo

nzk0hqpo3#

首先将# -*- coding: utf-8 -*-行添加到文件的开头,然后对所有非ASCII unicode数据使用u'foo'

def NewFunction():
    return u'£'

或者使用自Python 2.6以来的魔法使其自动化:

from __future__ import unicode_literals
axr492tv

axr492tv4#

错误消息会告诉你到底出了什么问题,Python解释器需要知道非ASCII字符的编码。
如果要返回U+00A3,则可以说

return u'\u00a3'

它通过Unicode转义序列在纯ASCII中表示该字符。如果要返回包含文本字节0xA 3的字节串,则

return b'\xa3'

(在Python 2中,b是隐式的;但是显式优于隐式)。
错误消息中链接的PEP * 确切地 * 指导您如何告诉Python“这个文件不是纯ASCII;这是我使用的编码”。如果编码是UTF-8,则为

# coding=utf-8

还是兼容Emacs的

# -*- encoding: utf-8 -*-

如果你不知道你的编辑器使用哪种编码来保存这个文件,你可以用十六进制编辑器或者谷歌搜索来检查一下。Stack Overflow character-encoding标签有一个tag info page,里面有更多的信息和一些故障排除技巧。
用这么多的话来说,在7位ASCII范围(0x 00 - 0x 7 F)之外,Python不能也不应该猜测一个字节序列代表什么字符串。https://tripleee.github.io/8bit#a3显示了字节0xA 3的21种可能的解释,而这只是来自传统的8位编码;但它也可以是多字节编码的第一个字节。但实际上,我猜您实际上使用的是Latin-1,所以您应该

# coding: latin-1

作为源文件的第一行或第二行。无论如何,如果不知道字节应该代表哪个字符,人类也不可能猜到这一点。
注意:coding: latin-1肯定会删 debugging 误消息(因为没有字节序列,这在技术上是不允许的),但如果实际编码是其他的,那么在解释代码时可能会产生完全错误的结果。在声明编码时,您必须完全确定地知道文件的编码。

vuv7lop3

vuv7lop35#

在脚本中添加以下两行代码为我解决了这个问题。

# !/usr/bin/python
# coding=utf-8

希望能有所帮助!

gz5pxeao

gz5pxeao6#

您可能正在尝试使用Python 2解释器来运行Python 3文件。目前(截至2019年),在Windows和大多数Linux发行版上,当两个版本都安装时,python命令默认为Python 2。
但是如果你确实在使用Python 2脚本,本页还没有提到的解决方案是以UTF-8+BOM编码重新保存文件,这将在文件的开头添加三个特殊字节,它们将显式地通知Python解释器(和文本编辑器)有关文件编码的信息。

b1payxdu

b1payxdu7#

总结

如果出现这个错误,使用一个 coding declaration 来告诉Python源代码(.py)文件的编码,没有这样的声明,Python 3.x将默认为UTF-8;Python 2.x将默认为ASCII。声明看起来像一个注解,包含一个标签coding:,后面跟着一个有效文本编码的名称。所有ASCII透明的编码都被支持。
例如:

#!/usr/bin/env python
# coding: latin-1

确保文件实际使用的编码以便编写正确的编码声明。有关提示,请参阅How to determine the encoding of text。或者,通过检查文本编辑器中的配置选项,尝试使用不同的编码。

问题
Every file on a computer is composed of raw bytes即使文件是“以文本模式”打开的,也不是固有的“文本”。当文件应该表示文本(例如Python程序的源代码)时,需要根据 * 编码 * 规则来解释它,以便理解数据。
但是,没有一种明显的方法可以从文件外部指示Python源文件的编码-例如,import语法不提供写入编码名称的位置(毕竟,它不一定是从源文件导入的)。因此,编码必须由文件内容本身以某种方式描述,Python需要一种方法来动态地确定这种编码。
为了让这个过程以一种一致和可靠的方式工作,Python从2.3版本开始,使用一个简单的引导过程来确定文件编码,这个过程被描述为by PEP 263

  • 首先,Python开始阅读文件的原始字节,如果它以UTF-8 encoded byte-order mark开头--字节0xEF 0xBB 0xBF--那么Python会丢弃这些字节,并指出文件的其余部分应该是UTF-8(以这种方式编写的文件有时被称为“utf-8-sig”编码)。
  • 接下来,Python尝试读取文件的下两行,使用默认编码(或者UTF-8,如果有字节顺序标记的话)-当然还有通用换行符:
  • 如果第一行不是注解(注意,shebang行在Python语法中也是注解),那么对文件的其余部分使用默认编码。
  • 否则,如果第一行是 encoding declaration(与特定正则表达式匹配的注解),则使用为文件其余部分声明的编码。
  • 否则,如果第二行是编码声明,则使用为文件其余部分声明的编码。
  • 否则,对文件的其余部分使用默认编码。
  • 如果文件以UTF-8字节顺序标记开头,* 并且 * 找到了UTF-8* 以外的编码声明 *,则会引发异常。
    Python检测到使用以下正则表达式的编码声明:
^[ \t\f]*#.*?coding[:=][ \t]*([-_.a-zA-Z0-9]+)

这个它旨在匹配其他工具(如Vim和Emacs文本编辑器)已经使用的几个标准编码声明。
编码声明的语法也被设计成只需要能用ASCII表示的字符。因此,任何“ASCII透明”编码都可以使用。默认编码也是ASCII透明的;因此,如果前两行包含编码声明,那么它将被正确读取,如果没有,那么相同的(默认)编码将被用于文件的其余部分。净效果是,就好像一直都假设了正确的编码,即使它不知道是从哪里开始的。聪明吧?
但是,请注意
UTF-16和其他非ASCII透明编码不受支持
。在此类编码中,编码声明无法使用默认编码读取,因此不会被处理。字节顺序标记也不能用于通知UTF-16:就是不承认,好像原来有计划支持这个,但是放弃了。
Python 3.x
PEP 3120将默认编码更改为UTF-8。因此,源文件can simply be saved with UTF-8 encoding, contain arbitrary text according to the Unicode standard and be used without an encoding declaration.plain 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文本(如£)时,需要编码声明。
注意,在Python 2.x中使用Unicode文本仍然需要Unicode常量,而不管源编码。指定编码可以允许Python 2.x将'ÿ'解释为有效的源代码(并且为Latin-1输入正确地指定Latin-1而不是UTF-8,可以允许它将该文本视为ÿ而不是ÿ),但它仍然是一个 byte 文本(不幸的是,它被称为str)。要创建一个实际的Unicode字符串,请确保使用u前缀或适当的“future import”:from __future__ import unicode_literals .

(But然后,为了使这样的字符串可打印,可能仍然需要do even moreespecially on 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\u86c7\U0001f9b6')
ø蛇🦶

无论源文件选择了什么编码,也无论是否声明了它(因为这个文本也是有效的ASCII和UTF-8),它都应该打印lowercase o with a line through itChinese hanzi/Japanese kanji表示“snake”和foot emoji(当然,假设您的终端支持这些字符)。
但是,此不能用于标识符名称:

>>> ø = 'monty' # no problem in 3.x; see https://peps.python.org/pep-3131/
>>> 蛇 = 'python' # although a foot emoji is not a valid identifier
>>> # however:
>>> \xf8 = 'monty'
  File "<stdin>", line 1
    \xf8 = 'monty'
                 ^
SyntaxError: unexpected character after line continuation character
>>> \u86c7 = 'python'
  File "<stdin>", line 1
    \u86c7 = 'python'
                    ^
SyntaxError: unexpected character after line continuation character

以这种方式报告错误是因为反斜杠(在带引号的字符串之外)是行继续符,并且它后面的所有内容都是非法的。

相关问题