【问题标题】:Python's UTF-8 encoding yields odd results even though explicit utf-8 encoding is used即使使用显式 utf-8 编码,Python 的 UTF-8 编码也会产生奇怪的结果
【发布时间】:2017-07-24 17:10:20
【问题描述】:

我正在解析一些 JSON(特别是亚马逊公开提供的亚马逊评论文件)。我正在逐行解析并转换为 Pandas DataFrame 并动态插入 SQL。我发现了一些非常奇怪的东西。我使用 UTF-8 打开 json 文件。当我用记事本打开文件本身时,我看不到任何奇怪的符号或其他任何东西。比如review的子串:

The temperature control doesn’t hold to as tight a temperature as some of the others reported.

但是当我解析它并检查字符串的内容时:

The temperature control doesn\xe2\x80\x99t hold to as tight a temperature as some of the others reported. 

为什么会这样?我怎么看不懂?

我当前的代码如下:

def parseJSON(path):
  g = io.open(path,'r',encoding='utf8')
  for l in g:
      yield eval(l)



for l in parseJSON(r"reviews.json"):
    for review in l["reviews"]:
        df = {}
        df[l["url"]] = review["review"]
        dfInsert = pd.DataFrame( list(df.items()), columns = ["url", "Review"])

失败的文件子集在那里: http://www.filedropper.com/subset

【问题讨论】:

  • 你为什么用eval而不是json.loads(...)?那可能是你的问题。还有python2还是python3?
  • @AnthonySottile 它是 2.7.13 |Continuum Analytics, Inc. 使用 json.loads() 结果完全相同
  • 文件是怎么写的?
  • doesn’t 中的撇号不是普通的单引号 ' == \x27,它是右单引号 == \u2019
  • 如果你想去掉花哨的引号等并用它们的纯 ASCII 等价物替换它们,看看Unidecode。最好让您的程序正确处理 Unicode,但这并不总是一种选择。

标签: python json encoding utf-8


【解决方案1】:

首先,您永远不应该使用eval 解析来自不安全(在线)来源的文本。如果数据在JSON 中,则应使用 JSON 解析器。这就是 JSON 被发明的原因 - 提供安全的序列化和反序列化。

在您的情况下,请使用标准 json 模块中的 json.load()

import json

def parseJSON(path):
    return json.load(io.open(path, 'r', encoding='utf-8-sig'))

由于您的 JSON 文件包含 BOM,因此您应该使用知道如何剥离它的编解码器,即 utf-8-sig

如果您的文件包含每行一个 JSON 对象,您可以这样读取:

def parseJSON(path):
    with io.open(path, 'r', encoding='utf-8-sig') as f:
        for line in f:
            yield json.loads(line)

现在回答为什么您看到的是doesn\xe2\x80\x99t 而不是doesn’t。如果您将字节 \xe2\x80\x99 解码为 UTF-8,您会得到:

>>> '\xe2\x80\x99'.decode('utf8')`
u'\u2019'

那是什么 Unicode 代码点?

>>> unicodedata.name(u'\u2019')
'RIGHT SINGLE QUOTATION MARK'

好的,现在当你在 Python 2 中 eval() 它时会发生什么?好吧,首先,请注意 Unicode 在 Python 2 字符串领域并不是真正的一等公民(Python 3 修复了这个问题)。

所以,eval 尝试将字符串(Python 2 中的字节序列)解析为 Python 表达式:

>>> eval('"’"')
'\xe2\x80\x99'

请注意(在我使用 UTF-8 的控制台中)即使我键入 ,它也表示为 3 个字节的序列。

说它应该是unicode 甚至没有帮助:

>>> eval('u"’"')
u'\xe2\x80\x99'

告诉 Python 如何解释源/字符串中的一系列字节,即编码是什么(参见 PEP-263):

>>> eval('# encoding: utf-8\nu"’"')
u'\u2019'

【讨论】:

  • 有道理,谢谢。但是 json.loads 产生完全相同的结果。当我尝试将这些东西加载到 SQL 中并得到它无法解码这个字节的错误时,我的问题就发生了。因此我认为文件读取步骤有问题。
  • 我是否正确,即使我看到这样的输出也不一定意味着文件没有被正确读取?
  • eval 无法正确处理 unicode。但是我们可以测试的唯一方法是您作为失败的示例输入给出的问题。
  • @MaximHaytovich,查看每行一个 JSON 对象的更新。
  • 谢谢,很有意义。尽管在这种情况下,我似乎必须为文件中可能遇到的每个奇怪符号重复相同的内容 - 还是依赖 Unidecode 或类似的东西?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-22
  • 2014-01-24
相关资源
最近更新 更多