【问题标题】:Trouble with utf-8 encoding/decodingutf-8 编码/解码问题
【发布时间】:2017-01-23 18:11:21
【问题描述】:

我正在阅读.csv,它是UTF-8 编码的。 我想创建一个索引并重写csv。 索引被创建为一个持续的数字一个单词的第一个字母。 Python 2.7.10,Ubuntu 服务器

#!/usr/bin/env python
# -*- coding: utf-8 -*-
counter = 0
tempDict = {}
with open(modifiedFile, "wb") as newFile:
    with open(originalFile, "r") as file:
        for row in file:
            myList = row.split(",")
            toId = str(myList[0])

            if toId not in tempDict:
                tempDict[toId] = counter
                myId = str(toId[0]) + str(counter)
                myList.append(myId)
                counter += 1
            else:
                myId = str(toId[0]) + str(tempDict[toId])
                myList.append(myId)

            # and then I write everything into the csv
            for i, j in enumerate(myList):
                if i < 6:
                    newFile.write(str(j).strip())
                    newFile.write(",")

                else: 
                    newFile.write(str(j).strip())
                    newFile.write("\n")

问题如下。 当单词以花哨的字母开头时,例如

  • Č
  • É
  • ?
  • ...

我创建的 id 以 ? 开头,但不以单词的字母开头。 奇怪的是,使用我创建的csv,带有花哨字母的单词是正确的。没有? 或其他表示错误编码的符号。

这是为什么呢?

【问题讨论】:

  • 你用的是什么版本的python?
  • 如果你在 Windows 上,它可能正在使用语言环境编码。
  • @TimMartin 2.7.10,正在处理Ubuntu Server
  • @JoshLee 在Ubuntu Server 上工作,然后我将文件下载到 Windows 计算机上。但是,当我检查 Ubuntu Server 上的文件时,该错误已经可见
  • 哦不! Sublime text 似乎用问号替换无效字节而没有任何警告或错误,这至少可以说是令人震惊的。

标签: python csv encoding utf-8


【解决方案1】:

无论如何,除非有你需要的 specific legacy C 扩展,否则你不应该学习 Python 2。

Python 3 对 unicode/bytes 处理进行了重大更改,消除了(大部分)隐式行为并使错误可见。使用open('filename', encoding='utf-8') 仍然是一种很好的做法,因为默认编码取决于环境和平台。

确实,在 Python 3 中运行您的程序应该无需任何更改即可修复它。但这是你的错误所在:

        toId = str(myList[0])

这是一个空操作,因为myList[0] 已经是str

            myId = str(toId[0]) + str(counter)

这是一个错误:toId 是一个包含 UTF-8 数据的str(字节字符串)。除了一次处理一个字符之外,您永远都不想对 UTF-8 数据做任何事情。

with open(originalFile, "r") as file:

这是一个样式错误,因为它掩盖了内置函数file

有两个变化可以让它在 Python 2 下运行。

  1. open(filename, mode) 更改为io.open(filename, mode, encoding='utf-8')
  2. 停止在字符串上调用str(),因为这实际上是在尝试对它们进行编码(在 ASCII 中!)。

但你真的应该切换到 Python 3。

2.6 和 2.7 的一些新功能旨在弥补与 3 的差距,其中之一是 io 模块,它以所有不错的新方式运行:Unicode 文件和通用换行符。

~$ python2.7 -c 'import io,sys;print(list(io.open(sys.argv[1],encoding="u8")))' <(printf $'\xc3\x84\r\n\xc3\xb9\r\n')
[u'\xc4\n', u'\xf9\n']
~$ python3 -c 'import sys;print(list(open(sys.argv[1],encoding="u8")))' <(printf $'\xc3\x84\r\n\xc3\xb9\r\n')
['Ä\n', 'ù\n']

这对于为 2 和 3 编写软件很有用。同样,编码参数是可选的,但在所有平台上,默认编码是依赖于环境的,所以最好是具体的。

【讨论】:

  • 在 Python 2 中,您应该使用 io.open(),它更接近 Py3 open() 并提供适当的通用线路支持
  • 谢谢,我的 2to3 有点生锈了 :)
【解决方案2】:

在 python 2.x 中,字符串默认是非 unicode - str() 返回一个非 unicode 字符串。请改用unicode()

此外,您必须使用utf-8 编码通过codecs.open() 而不是内置的open() 打开文件。

【讨论】:

  • 嗯,但是为什么其他单词编码正确?升级到 python 3.x 会解决这个问题吗?
  • @Stophface 为什么其他单词编码正确toId[0] 中,当toId 恰好以多字节字符开头时,您实际上只取了它的第一个字节因此它不再是一个有效的字符。其余的处理只是简单地复制输入数据(用逗号分隔不会引入任何问题)。
  • @Stophface 升级到 python 3.x 能解决这个问题吗 是的
  • 哇哦。我不知道它只占用第一个字节。我认为python“知道”这些字节属于一起,然后把它们全部拿走。
  • @Stophface 我认为python“知道”这些字节属于一起它对unicode字符串这样做。但正如我在答案中所写,str 类型的 Python 2.x(与 Python 3.x 不同)是非 unicode 字符串。
猜你喜欢
  • 1970-01-01
  • 2013-03-26
  • 2018-02-18
  • 2010-12-01
  • 1970-01-01
  • 2018-06-06
相关资源
最近更新 更多