ChatGPT解决这个技术问题 Extra ChatGPT

在 Python 中将 Unicode 转换为 ASCII 而不会出错

我的代码只是抓取一个网页,然后将其转换为 Unicode。

html = urllib.urlopen(link).read()
html.encode("utf8","ignore")
self.response.out.write(html)

但我得到一个 UnicodeDecodeError

Traceback (most recent call last):
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/webapp/__init__.py", line 507, in __call__
    handler.get(*groups)
  File "/Users/greg/clounce/main.py", line 55, in get
    html.encode("utf8","ignore")
UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 2818: ordinal not in range(128)

我认为这意味着 HTML 在某处包含一些格式错误的 Unicode 尝试。我可以只删除导致问题的任何代码字节而不是出错吗?

似乎您可能在网页中遇到了“无中断空间”?需要以 c2 字节开头,否则您可能会收到解码错误:hexutf8.com/?q=C2A0
应该修改这个问题的图块,以表明它专门关于解析 HTML 请求的结果,而不是关于“在 Python 中将 Unicode 转换为 ASCII 而不会出错”。
提醒任何 txt 看起来像这样的人:\x1b[38;5;226m... 它是 ansi escape codes,而不是 unicode。

M
Michael
>>> u'aあä'.encode('ascii', 'ignore')
'a'

使用响应中相应 meta 标记或 Content-Type 标头中的字符集对您返回的字符串进行解码,然后进行编码。

方法 encode(encoding, errors) 接受错误的自定义处理程序。除 ignore 外,默认值为:

>>> u'aあä'.encode('ascii', 'replace')
b'a??'
>>> u'aあä'.encode('ascii', 'xmlcharrefreplace')
b'aあä'
>>> u'aあä'.encode('ascii', 'backslashreplace')
b'a\\u3042\\xe4'

请参阅https://docs.python.org/3/library/stdtypes.html#str.encode


忽略字符根本不是解决方案。它应该是 á → a、é → e 等……因为重音字符在西班牙语中并不那么重要,但它是一种帮助您发音的简单方法。您必须映射字符,因为 iconv 或任何其他 i = orig.find(x); if i >= 0: x = dest[I] 都没有解决方案,其中 original 类似于:origL = 'áéíóúüç'dest=destL = 'aeiouuc'
C
Community

作为 Ignacio Vazquez-Abrams 回答的延伸

>>> u'aあä'.encode('ascii', 'ignore')
'a'

有时需要从字符中删除重音符号并打印基本形式。这可以通过

>>> import unicodedata
>>> unicodedata.normalize('NFKD', u'aあä').encode('ascii', 'ignore')
'aa'

您可能还想将其他字符(如标点符号)翻译成最接近的等价物,例如,在编码时,右单引号 unicode 字符不会转换为 ascii APOSTROPHE。

>>> print u'\u2019'
’
>>> unicodedata.name(u'\u2019')
'RIGHT SINGLE QUOTATION MARK'
>>> u'\u2019'.encode('ascii', 'ignore')
''
# Note we get an empty string back
>>> u'\u2019'.replace(u'\u2019', u'\'').encode('ascii', 'ignore')
"'"

尽管有更有效的方法来实现这一点。有关详细信息,请参阅此问题 Where is Python's "best ASCII for this Unicode" database?


既有助于解决所提出的问题,又有助于解决可能构成所提问题的问题。这是此类问题的典型答案。
j
jalanb

2018 年更新:

截至 2018 年 2 月,使用 gzip 之类的压缩已成为 quite popular(大约 73% 的所有网站都在使用它,包括 Google、YouTube、Yahoo、Wikipedia、Reddit、Stack Overflow 和 Stack Exchange Network 网站等大型网站)。< br> 如果您在原始答案中使用 gzip 响应进行简单解码,您将收到类似或类似以下的错误:

UnicodeDecodeError:“utf8”编解码器无法解码位置 1 的字节 0x8b:意外的代码字节

为了解码 gzpipped 响应,您需要添加以下模块(在 Python 3 中):

import gzip
import io

注意: In Python 2 you'd use StringIO instead of io

然后你可以像这样解析内容:

response = urlopen("https://example.com/gzipped-ressource")
buffer = io.BytesIO(response.read()) # Use StringIO.StringIO(response.read()) in Python 2
gzipped_file = gzip.GzipFile(fileobj=buffer)
decoded = gzipped_file.read()
content = decoded.decode("utf-8") # Replace utf-8 with the source encoding of your requested resource

此代码读取响应,并将字节放入缓冲区。 gzip 模块然后使用 GZipFile 函数读取缓冲区。之后,可以再次将 gzip 压缩文件读入字节并最终解码为正常可读的文本。

2010年的原始答案:

我们能得到用于 link 的实际值吗?

另外,当我们试图.encode()一个已经编码的字节串时,我们通常会在这里遇到这个问题。所以你可能会尝试先解码它,如

html = urllib.urlopen(link).read()
unicode_str = html.decode(<source encoding>)
encoded_str = unicode_str.encode("utf8")

举个例子:

html = '\xa0'
encoded_str = html.encode("utf8")

失败

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

尽管:

html = '\xa0'
decoded_str = html.decode("windows-1252")
encoded_str = decoded_str.encode("utf8")

成功无误。请注意,“windows-1252”是我用作示例的东西。我从 chardet 得到这个,它有 0.5 的信心认为它是正确的! (好吧,正如给出的 1 个字符长度的字符串,您期望什么)您应该将其更改为从 .urlopen().read() 返回的字节字符串的编码,以适用于您检索的内容。

我看到的另一个问题是 .encode() 字符串方法返回修改后的字符串并且没有修改源。因此,拥有 self.response.out.write(html) 是没有用的,因为 html 不是来自 html.encode 的编码字符串(如果那是您最初的目标)。

正如 Ignacio 建议的那样,检查源网页以了解从 read() 返回的字符串的实际编码。它位于 Meta 标记之一或响应的 ContentType 标头中。然后将其用作 .decode() 的参数。

但是请注意,不应假定其他开发人员有足够的责任来确保标头和/或元字符集声明与实际内容匹配。 (这是一个 PITA,是的,我应该知道,我以前是其中之一)。


在您的示例中,我认为您的意思是最后一行是 encoded_str = decoded_str.encode("utf8")
我在 Python 2.7.15 中尝试过,我收到了这条消息 raise IOError, 'Not a gzipped file'。我做错了什么?
K
K DawG

使用 unidecode - 它甚至可以将奇怪的字符立即转换为 ascii,甚至将中文转换为拼音 ascii。

$ pip install unidecode

然后:

>>> from unidecode import unidecode
>>> unidecode(u'北京')
'Bei Jing'
>>> unidecode(u'Škoda')
'Skoda'

halle-freakin-lujah - 是时候找到适合我的答案了
为有趣的价值而投票。请注意,这会破坏所有重读语言中的单词。斯柯达不是斯柯达。斯柯达很可能意味着鳗鱼和气垫船的恶心。
直到现在我一直在网上搜索......谢谢,非常感谢
G
Gattster

我在所有项目中都使用这个辅助函数。如果它不能转换 unicode,它会忽略它。这与 django 库有关,但稍加研究您就可以绕过它。

from django.utils import encoding

def convert_unicode_to_string(x):
    """
    >>> convert_unicode_to_string(u'ni\xf1era')
    'niera'
    """
    return encoding.smart_str(x, encoding='ascii', errors='ignore')

使用它后,我不再收到任何 unicode 错误。


那是抑制问题,而不是诊断和修复。这就像在说“在我切掉我的脚之后,我不再有鸡眼和拇囊炎的问题”。
我同意它正在压制问题。似乎这就是问题所在。看看他的笔记:“我可以删除导致问题的任何代码字节而不是出错吗?”
这与简单地调用 "some-string".encode('ascii', 'ignore') 完全相同
我无法告诉你我对有人提出关于 SO 的问题并得到所有这些说教的回答有多累。 “我的车发动不了。” “你为什么要发动你的车?你应该走路。”停下来!
在非常真实的项目中有非常真实的商业案例,资金非常大,是的,放弃这些角色是绝对可以的。
c
ccpizza

对于 cmd.exe 和 HTML 输出等损坏的控制台,您始终可以使用:

my_unicode_string.encode('ascii','xmlcharrefreplace')

这将保留所有非 ascii 字符,同时使它们可以在纯 ASCII 和 HTML 中打印。

警告:如果您在生产代码中使用它来避免错误,那么您的代码很可能有问题。唯一有效的用例是打印到非 unicode 控制台或在 HTML 上下文中轻松转换为 HTML 实体。

最后,如果您在 Windows 上使用 cmd.exe,则可以键入 chcp 65001 以启用 utf-8 输出(使用 Lucida Console 字体)。您可能需要添加 myUnicodeString.encode('utf8')


J
John Machin

你写了“”“我认为这意味着 HTML 在某处包含一些格式错误的 unicode 尝试。”“”

HTML 不应包含任何类型的“尝试 unicode”,无论格式是否正确。它必须包含以某种编码方式编码的 Unicode 字符,这通常是预先提供的……寻找“字符集”。

您似乎假设字符集是 UTF-8 ...基于什么理由?错误消息中显示的“\xA0”字节表明您可能有一个单字节字符集,例如 cp1252。

如果您无法理解 HTML 开头的声明,请尝试使用 chardet 找出可能的编码是什么。

为什么你用“正则表达式”标记你的问题?

用非问题替换整个问题后更新:

html = urllib.urlopen(link).read()
# html refers to a str object. To get unicode, you need to find out
# how it is encoded, and decode it.

html.encode("utf8","ignore")
# problem 1: will fail because html is a str object;
# encode works on unicode objects so Python tries to decode it using 
# 'ascii' and fails
# problem 2: even if it worked, the result will be ignored; it doesn't 
# update html in situ, it returns a function result.
# problem 3: "ignore" with UTF-n: any valid unicode object 
# should be encodable in UTF-n; error implies end of the world,
# don't try to ignore it. Don't just whack in "ignore" willy-nilly,
# put it in only with a comment explaining your very cogent reasons for doing so.
# "ignore" with most other encodings: error implies that you are mistaken
# in your choice of encoding -- same advice as for UTF-n :-)
# "ignore" with decode latin1 aka iso-8859-1: error implies end of the world.
# Irrespective of error or not, you are probably mistaken
# (needing e.g. cp1252 or even cp850 instead) ;-)

P
Paul Rigor

如果您有字符串 line,则可以使用字符串的 .encode([encoding], [errors='strict']) 方法来转换编码类型。

line = 'my big string'

line.encode('ascii', 'ignore')

有关在 Python 中处理 ASCII 和 unicode 的更多信息,这是一个非常有用的站点:https://docs.python.org/2/howto/unicode.html


当字符串中有 ü 这样的非 ascii 字符时,这不起作用。
S
Somum

我认为答案就在那里,但只是零碎的,这使得很难快速解决问题,例如

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

举个例子,假设我有一个文件,其中包含以下形式的一些数据(包含 ascii 和非 ascii 字符)

2017 年 1 月 10 日,21:36 - 土地:欢迎 ��

我们想忽略并只保留 ascii 字符。

此代码将执行以下操作:

import unicodedata
fp  = open(<FILENAME>)
for line in fp:
    rline = line.strip()
    rline = unicode(rline, "utf-8")
    rline = unicodedata.normalize('NFKD', rline).encode('ascii','ignore')
    if len(rline) != 0:
        print rline

和 type(rline) 会给你

>type(rline) 
<type 'str'>

这也适用于(非标准化)“扩展 ascii”案例
H
HimalayanCoder
unicodestring = '\xa0'

decoded_str = unicodestring.decode("windows-1252")
encoded_str = decoded_str.encode('ascii', 'ignore')

为我工作


F
Faisal Nazik

您可以使用以下代码作为示例来避免 Unicode 到 ASCII 错误:

from anyascii import anyascii

content = "Base Rent for – CC# 2100 Acct# 8410: $41,667.00 – PO – Lines - for Feb to Dec to receive monthly"
content = anyascii(content)
print(content)

H
Haroon Rashedu

看起来你正在使用 python 2.x。 Python 2.x 默认为 ascii,它不知道 Unicode。因此例外。

只需在shebang之后粘贴以下行,它就会起作用

# -*- coding: utf-8 -*-

coding 评论不是万灵药。你需要知道为什么会产生错误,这只会在你的 Python 源代码中有坏字符时修复问题。对于这个问题,情况似乎并非如此。