12

我正在尝试处理 python 2.7.2 中的 unicode。我知道有这样的.encode('utf-8')东西,但是当我添加它时,有 1/2 的时间会出错,而当我不添加它的时候,有 1/2 的时间会出错。

有什么方法可以告诉 python - 我认为是一种最新和现代的语言,只使用 unicode 作为字符串,而不是让我不得不放屁.encode('utf-8')

我知道... python 3.0 应该做到这一点,但我不能使用 3.0 和 2.7 反正不是那么旧...

例如:

url = "http://en.wikipedia.org//w/api.php?action=query&list=search&format=json&srlimit=" + str(items) + "&srsearch=" + urllib2.quote(title.encode('utf-8'))
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 19: ordinal not in range(128)

更新 如果我.encode从我的所有代码中删除我的所有语句并添加# -*- coding: utf-8 -*-到我的文件顶部,#!/usr/bin/python那么我得到以下内容,就像我根本没有添加一样# -*- coding: utf-8 -*-

/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib.py:1250: UnicodeWarning: Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal
  return ''.join(map(quoter, s))
Traceback (most recent call last):
  File "classes.py", line 583, in <module>
    wiki.getPage(title)
  File "classes.py", line 146, in getPage
    url = "http://en.wikipedia.org/w/api.php?action=query&prop=revisions&format=json&rvprop=content&rvlimit=1&titles=" + urllib2.quote(title)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib.py", line 1250, in quote
    return ''.join(map(quoter, s))
KeyError: u'\xf1'

我没有手动输入任何字符串,而是从网站解析 HTML 和 json。所以脚本/字节流/无论它们是什么,都是由python创建的。

更新 2我可以移动错误,但它只是不断出现在新的地方。我希望 python 会成为一个有用的脚本工具,但看起来在 3 天没有运气之后我会尝试另一种语言。很遗憾,python 预装在 osx 上。我已将修复我发布的错误的一个实例的答案标记为正确。

4

5 回答 5

20

这是一个非常古老的问题,但只想添加一个部分建议。虽然我同情 OP 的痛苦——我自己经历了很多——但这里有一个(部分)答案,可以让事情“更轻松”。把它放在任何 Python 2.7 脚本的顶部:

from __future__ import unicode_literals

这至少可以确保您自己的文字字符串默认为 unicode 而不是 str。

于 2013-10-29T09:40:59.820 回答
18

除了在任何地方使用 unicode 字符串并立即解码您收到的任何编码字符串之外,没有办法让 unicode “正常工作”。问题是,无论您是在处理编码数据还是未编码数据,或者使用为您跟踪数据的工具,您都必须始终保持直截了当,否则您将度过一段糟糕的时光。

Python 2 做了一些有问题的事情:它使str“默认”而不是字符串文字之类的东西,当您添加两者时unicode它会默默地强制str转换,并且它允许您调用已经编码的字符串进行双重编码它。结果,有很多 python 编码器和 python 库不知道它们设计用于使用什么编码,但仍然设计用于处理某些特定编码,因为该类型旨在让程序员管理编码本身。每次使用这些库时都必须考虑编码,因为它们本身不支持该类型。unicode.encode()strunicode


在您的特定情况下,第一个错误告诉您正在处理编码的 UTF-8 数据并尝试对其进行双重编码,而第二个错误告诉您正在处理未编码的数据。看起来你可能两者都有。你真的应该找到并解决问题的根源(我怀疑它与我上面提到的无声强制有关),但这里有一个应该在短期内解决它的 hack:

encoded_title = title
if isinstance(encoded_title, unicode):
    encoded_title = title.encode('utf-8')

如果这实际上是一种无声强制咬你的情况,你应该能够使用优秀的unicode-nazi工具轻松追踪问题:

python -Werror -municodenazi myprog.py

这将在 unicode 泄漏到您的非 unicode 字符串时为您提供追溯,而不是尝试从实际问题开始排除这种异常。有关详细信息,请参阅我对这个相关问题的回答。

于 2012-09-23T23:52:19.887 回答
3

是的,将您的 unicode 数据定义为 unicode 文字:

>>> u'Hi, this is unicode: üæ'
u'Hi, this is unicode: üæ'

您通常希望使用 '\uxxxx` unicode 转义或设置源代码编码。例如,模块顶部的以下行将编码设置为 UTF-8:

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

阅读Python Unicode HOWTO了解详细信息,例如默认编码等(例如,默认源代码编码是 ASCII)。

至于您的具体示例,您的标题不是 Unicode 文字而是 python 字节字符串,python 正在尝试为您将其解码un​​icode,以便您可以再次对其进行编码。这失败了,因为这种自动编码的默认编解码器是 ASCII:

>>> 'å'.encode('utf-8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)

编码仅适用于实际的 unicode 字符串,因此需要显式解码字节字符串:

>>> 'å'.decode('utf-8').encode('utf-8')
'\xc3\xa5'

如果您习惯了 Python 3,那么 Python 2 ( u'') 中的 unicode 文字是 Python 3 中新的默认字符串类型,而 Python 2 ( ) 中的常规(字节)字符串与 Python 3 ( ) 中的对象''相同。bytesb''

如果您在使用和不使用编码调用时都有错误title,则您有混合数据。根据需要测试标题和编码:

if isinstance(title, unicode):
    title = title.encode('utf-8')

您可能想找出产生混合 unicode / 字节字符串标题的原因,并更正该源以始终产生一个或另一个。

于 2012-09-23T23:07:03.447 回答
2

确保 title.encode("utf-8") 中的标题是 unicode 类型,不要使用 str("İŞşĞğÖöÜü")

在你的字符串化器中使用 unicode("ĞğıIİiÖöŞşcçÇ")

于 2012-09-23T23:12:27.950 回答
2

实际上,让 Python 与 unicode 一起工作的最简单方法是使用 Python 3,默认情况下所有内容都是 unicode。

不幸的是,为 P3 编写的库并不多,在编码和关键字使用方面也存在一些基本差异。这就是我遇到的问题:我需要的库仅适用于 P 2.7,我不知道将它们转换为 P 3。:(

于 2013-02-28T21:34:33.387 回答