【问题标题】:Python & fql: getting "Dami\u00e1n" instead of "Damián"Python & fql:得到“Dami\u00e1n”而不是“Damián”
【发布时间】:2012-09-16 21:28:23
【问题描述】:

我创建了一个包含字典的文件,其中包含用西班牙语编写的数据(即 Damián 等):

fileNameX.write(json.dumps(dictionaryX, indent=4))

数据来自一些fql抓取操作,即:

select name from user where uid in XXX

当我打开文件时,例如,我发现“Damián”看起来像“Dami\u00e1n”。 我尝试了一些选项:

  1. ensure_ascii=False:

    fileNameX.write(json.dumps(dictionaryX, indent=4, ensure_ascii=False))
    

    但我收到一个错误(UnicodeEncodeError: 'ascii' codec can't encode character u'\xe1' in position XXX: ordinal not in range(128))。

  2. 编码(encoding='latin-1):

    dictionaryX.append({
        'name': unicodeVar.encode(encoding='latin-1'),
         ...
         })
    

    但我得到另一个错误(UnicodeDecodeError: 'utf8' codec can't decode byte 0xe1 in position XXX: invalid continuation byte

总而言之,我尝试了几种可能性,但没有一个线索。我迷路了。拜托,我需要帮助。谢谢!

【问题讨论】:

  • 这不正确吗?根据 JSON 标准,非 ASCII 字符可以使用 unicode 转义来表示……所以文件似乎包含正确的数据!

标签: python json unicode encoding facebook-fql


【解决方案1】:

您有很多选择,并且偶然发现了一些相当复杂的东西,这取决于您的 Python 版本,并且您必须完全理解才能编写正确的代码。一般来说,3.x 中采用的方法更严格,也更难使用,但你犯错误或陷入复杂情况的可能性要小得多。 (根据您报告的确切症状,您似乎使用的是 2.x。)

json.dumps 在 2.x 和 3.x 中具有不同的行为。在 2.x 中,它产生一个str,它是一个字节串(未知编码)。在 3.x 中,它仍然会生成一个 str,但现在 3.x 中的 str 是一个正确的 Unicode 字符串。

JSON 本质上是一种支持 Unicode 的格式,但它要求文件采用 UTF-8 编码。但是,请理解 JSON 支持字符串中的\u 样式转义。当您读入此数据时,您将获得正确的编码字符串。读取代码从 JSON 中读取字符串时会生成 unicode 对象(无论您使用的是 2.x 还是 3.x)。

当我打开文件时,我发现例如“Damián”看起来像“Dami\u00e1n”

á 不能用 ASCII 表示。默认情况下,它被编码为\u00e1,以避免您遇到的其他问题。即使在 3.x 中也会发生这种情况。

ensure_ascii=False

这会禁用以前的编码。在 2.x 中,这意味着您将获得一个 unicode 对象 - 一个真正的 Unicode 对象,保留原始的 á 字符。在 3.x 中,这意味着该字符没有被显式翻译。但无论哪种方式,ensure_ascii=False 意味着 json.dumps 会给你一个 Unicode 字符串

Unicode 字符串必须经过编码才能写入文件。没有“unicode 数据”之类的东西; Unicode 是一种抽象。在 2.x 中,当您将 Unicode 对象提供给 file.write 时,此编码隐式为 'ascii';它期待一个str。为了解决这个问题,您可以使用codecs 模块,或者在编写之前显式编码为'utf-8'。在 3.x 中,当您 open 文件时,使用 encoding 关键字参数设置编码(默认值可能又不是您想要的)。

编码(encoding='latin-1')

在这里,您在生成字典之前进行编码,因此您的数据中有一个str 对象。现在出现了一个问题,因为当您的数据中有 str 对象时,JSON 编码器默认假定它们代表 Unicode 字符串UTF-8 编码。这可以在 2.x 中使用 encoding 关键字参数更改为 json.dumps。 (在 3.x 中,编码器将简单地拒绝序列化 bytes 对象,即非 Unicode 字符串!)


但是,如果您的目标只是将数据直接放入文件中,那么 json.dumps 不适合您。你有没有想过名字中的s 是干什么用的?它代表“字符串”;这是特例。普通情况,其实就是直接写入文件! (而不是给你一个字符串并期望你自己写。)这就是json.dump(没有's')所做的。同样,JSON 标准需要 UTF-8 编码,并且 2.x 有一个 encoding 关键字参数,默认为 UTF-8(您应该不理会它)。

【讨论】:

    【解决方案2】:

    使用codecs.open() 打开fileNameX 具有特定编码 例如encoding='utf-8',而不是使用open()

    另外,json.dump()

    【讨论】:

    • 对不起,我还是很迷茫。即使我使用了 print json.dumps(dictionaryX, indent=4),我也希望看到“Damián”
    • 假设我在 shell 中执行此操作:>>>a = 'Dami\u00e1n'。然后我做>>>打印一个。我会得到:Dami\u00e1。当我做>>>打印whatever_modifying_a时,我应该怎么做才能得到Damián?谢谢!
    • 让 unicode 字符串在你的 shell 中正确显示是一个完全独立的问题!但在 2.x 中,这无论如何都不是 Unicode 字符串。试试a = u'Dami\u00e1n'。请注意,当您load JSON 数据时,json 将为您翻译这些转义。
    【解决方案3】:

    因为字符串里面有一个\u,这意味着它是一个Unicode字符串。字符串实际上是正确的!您的问题在于显示字符串。如果您 print 字符串,Python 的输出编码应该以适合您环境的正确编码打印它。

    例如,这是我在 Windows 上的 IDLE 中得到的:

    >>> print u'Dami\u00e1n'
    Damián
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-11-22
      • 2012-11-02
      • 2023-03-10
      • 2019-05-01
      • 2021-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多