在Python中将Unicode转换为ASCII而没有错误

the*_*ror 170 python unicode ascii utf-8 character-encoding

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

html = urllib.urlopen(link).read()
html.encode("utf8","ignore")
self.response.out.write(html)
Run Code Online (Sandbox Code Playgroud)

但我得到一个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)
Run Code Online (Sandbox Code Playgroud)

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

Ign*_*ams 209

>>> u'a?ä'.encode('ascii', 'ignore')
'a'
Run Code Online (Sandbox Code Playgroud)

编辑:

使用meta响应中或Content-Type标题中相应标记中的字符集解码您获得的字符串,然后进行编码.

该方法encode(encoding, errors)接受其他值为"ignore".例如:'replace','xmlcharrefreplace','backslashreplace'.请参阅https://docs.python.org/3/library/stdtypes.html#str.encode


Pet*_*son 118

作为Ignacio Vazquez-Abrams答案的延伸

>>> u'a?ä'.encode('ascii', 'ignore')
'a'
Run Code Online (Sandbox Code Playgroud)

有时需要从字符中删除重音并打印基本表单.这可以通过以下方式实现

>>> import unicodedata
>>> unicodedata.normalize('NFKD', u'a?ä').encode('ascii', 'ignore')
'aa'
Run Code Online (Sandbox Code Playgroud)

您可能还希望将其他字符(例如标点符号)转换为最接近的等效字符,例如,在编码时,RIGHT SINGLE QUOTATION MARK 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')
"'"
Run Code Online (Sandbox Code Playgroud)

虽然有更有效的方法来实现这一目标.有关更多详细信息,请参阅此问题Python的"此Unicode的最佳ASCII"数据库在哪里?

  • 两者都有助于解决所提出的问题,并且可以解决可能存在问题的问题.这是这类问题的模型答案. (4认同)

Vin*_*n-G 102

2018年更新:

截至2018年2月,使用压缩gzip已经变得非常流行(大约73%的网站使用它,包括谷歌,YouTube,雅虎,维基百科,Reddit,Stack Overflow和Stack Exchange网站等大型网站).
如果你使用gzip响应进行原始答案中的简单解码,你会收到类似或类似的错误:

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

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

import gzip
import io
Run Code Online (Sandbox Code Playgroud)

注意: 在Python 2中,您将使用StringIO而不是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
Run Code Online (Sandbox Code Playgroud)

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

2010年的原始答案:

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

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

html = urllib.urlopen(link).read()
unicode_str = html.decode(<source encoding>)
encoded_str = unicode_str.encode("utf8")
Run Code Online (Sandbox Code Playgroud)

举个例子:

html = '\xa0'
encoded_str = html.encode("utf8")
Run Code Online (Sandbox Code Playgroud)

失败了

UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 0: ordinal not in range(128)
Run Code Online (Sandbox Code Playgroud)

而:

html = '\xa0'
decoded_str = html.decode("windows-1252")
encoded_str = decoded_str.encode("utf8")
Run Code Online (Sandbox Code Playgroud)

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

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

正如Ignacio所建议的那样,检查源网页上的返回字符串的实际编码read().它位于Meta标签之一或响应中的ContentType标头中.然后使用它作为参数.decode().

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


Nim*_*imo 89

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

$ pip install unidecode
Run Code Online (Sandbox Code Playgroud)

然后:

>>> from unidecode import unidecode
>>> unidecode(u'??')
'Bei Jing'
>>> unidecode(u'Škoda')
'Skoda'
Run Code Online (Sandbox Code Playgroud)

  • 为有趣的价值而投票.请注意,这会破坏所有强调语言中的单词.斯柯达不是斯柯达.斯柯达最有可能意味着与鳗鱼和气垫船有关. (9认同)
  • halle-freakin-lujah - 它的时间我找到了一个对我有用的答案 (3认同)

Gat*_*ter 23

我在所有项目中使用这个辅助函数.如果它无法转换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')
Run Code Online (Sandbox Code Playgroud)

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

  • 我不能告诉你我是多么厌倦有人在问这个问题,并得到所有这些有说服力的回答."我的车不会启动." "你为什么要开车?你应该走路." 停下来! (17认同)
  • 这是解决问题,而不是诊断和修复.这就像是说"我脱掉脚后,我不再有玉米和拇囊炎的问题". (10认同)
  • 我同意它正在压制这个问题.看起来这就是问题之后的问题.看看他的笔记:"我可以删除引起问题的代码字节而不是出错吗?" (10认同)
  • @JohnMachin无人问津.我不在乎什么迟钝的垃圾人放在RSS源,如果它是一些字符不在ascii它可以被截断.他们的问题.我只是想让python实际上把它扼杀并处理它,而不是每次指定'ignore'时都给我错误.到底是谁想出那个狗屎?! (8认同)
  • 这与简单地调用"some-string"完全相同.encode('ascii','ignore') (3认同)
  • 在非常实际的项目中有很多非常实际的商业案例,其中,是的,放弃这些字符是绝对可以的. (3认同)
  • 而那个问题的答案应该是响亮的**NO !!**他已经有一个错误,忽略它更糟! (2认同)
  • @ user1244215我完全同意这一点,但不是你在解释上述观点时选择的用语. (2认同)
  • @shanusmagnus如果讲道的人是主持人,情况会更糟.他只是投票结束你的问题!! 程序员种族主义 (2认同)

ccp*_*zza 10

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

my_unicode_string.encode('ascii','xmlcharrefreplace')
Run Code Online (Sandbox Code Playgroud)

这将保留所有非ascii字符,同时使它们以纯ASCII HTML格式打印.

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

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


Joh*_*hin 6

你写了"""我认为这意味着HTML包含某些错误形成的unicode尝试.""

HTML不应该包含任何类型的"unicode尝试",格式是否良好.它必须包含以某种编码编码的Unicode字符,通常在前面提供...寻找"charset".

您似乎假设字符集是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) ;-)
Run Code Online (Sandbox Code Playgroud)


Jam*_*a22 5

如果你有一个 string line,你可以使用string的.encode([encoding], [errors='strict'])方法来转换编码类型。

line = 'my big string'

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

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


Som*_*mum 5

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

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

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

1/10/17, 21:36 - Land : 欢迎 ��

我们只想忽略和保留 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
Run Code Online (Sandbox Code Playgroud)

和 type(rline) 会给你

>type(rline) 
<type 'str'>
Run Code Online (Sandbox Code Playgroud)