以UTF-8编码的“Broken”unicode字符串?

时间:2010-03-10 09:10:27

标签: python django unicode utf-8

我一直在研究unicode及其Python实现两天,我想我已经看到了它的含义。为了获得自信,我问我对当前问题的假设是否正确。

在Django中,表单给了我unicode字符串,我怀疑它是“破碎的”。 Python中的Unicode字符串应该用UTF-8编码,是吗?在文本字段中输入字符串“fähre”后,浏览器会在POST请求中发送字符串“f%c3%a4hre”(通过wireshark检查)。当我通过form.cleaned_data检索值时,我得到字符串u'f \ xa4hre'(注意它是一个unicode字符串)。据我了解,那是ISO-8859-1编码的unicode字符串,这是不正确的。正确的字符串应该是u'f \ xc3 \ xa4hre',这将是一个UTF-8编码的unicode字符串。这是一个Django错误还是我对它的理解有问题? 为了解决这个问题,我编写了一个函数将它应用于任何来自Django表单的文本输入:

def fix_broken_unicode(s):
    return unicode(s.encode(u'utf-8'), u'iso-8859-1')

哪个

>>> fix_broken_unicode(u'f\xa4hre')
u'f\xc3\xa4hre'

这对我来说似乎并不优雅,但将Django的settings.DEFAULT_CHARSET设置为'utf-8'没有帮助,也没有做任何其他事情。我试图在整个应用程序中使用unicode,因此我不会在以后遇到任何奇怪的错误,但显然不足以用u'...'标记所有字符串。

编辑:考虑到Dirk和某些人的答案,我现在将字符串保存到数据库中。真正的问题是我试图对这些类型的字符串进行urlencode以将它们用作Twitter API等的输入。但是,在GET或POST请求中,显然需要UTF-8编码,标准urllib.urlencode()函数会执行此操作。不正确处理(抛出异常)。在pastebin中查看我的解决方案,也可以对其进行评论。

2 个答案:

答案 0 :(得分:4)

u'f\xa4hre'是一个unicode字符串,未编码为任何内容。 unicode代码点0xa4是字符ä。 {_ 1}}在ISO-8859-1中也被编码为字节ä并不重要。

unicode字符串可以包含任何unicode字符,而不以某种方式对它们进行编码。例如,0xa4将表示为轮渡,它们只是两个unicode代码点。 UTF-8编码将更长u'\u8f6e\u6e21'

因此无需修复编码,您只是看到了unicode字符串的内部表示。

答案 1 :(得分:1)

不完全是:解码后,unicode字符串是 unicode ,这意味着它可能包含代码超过255的字符。解释器如何表示这些取决于平台,但现在通常使用宽度至少为16位的字符元素。 ISO-8859-1是unicode的合适子集。因此,字符串u'f\xa4hre'实际上是正确的 - \xa4是一个渲染工件,因为Python不知道是否(以及何时)包含代码超出特定范围的字符是安全的控制台。

UTF-8是传输编码,这是一种编写unicode数据的特殊方法,它可以存储在“通道”中,每个字符/字节的元素宽度为8位。为了计算unicode字符串的正确“外部”(或传输)编码,您需要使用encode方法,传递所需的表示。它返回一个正确编码的字节字符串(而不是unicode字符串)。

反向转换为decode,它采用字节字符串和编码名称,并生成unicode 字符串