Mik*_*e91 3 python csv unicode python-2.7 python-3.x
我有以下代码读取csv文件(一些包含非UTF8字符).它在Python 2.7.x中运行良好:
encodings = {'ukprocessed.csv': 'utf8',
'usprocessed.csv': 'utf8',
'uyprocessed.csv': 'latin1',
'arprocessed.csv': 'latin1'}
with codecs.open(filepath, 'r') as csvfile:
reader = csv.reader(csvfile)
for row in reader:
row = [x.decode(encodings[filename]).encode('utf8') for x in row]
Run Code Online (Sandbox Code Playgroud)
但是,在Python 3.4.x中,测试失败并出现各种错误:
我已经玩过在open文件中指定'encoding =',用'rb'和其他一些东西打开字节,但我找不到适用于Python 2和3的解决方案.
有没有人对我如何解决这个问题有任何想法?
谢谢
在Py3中,x每个row中的值都是str(类似于Py2 unicode).在Py2中,str并且unicode过于灵活,因为str它既是文本又是二进制数据类型; 它支持encode,通过假设str是ASCII,解码它,然后重新编码为选择的编码(对于ASCII兼容编解码器是没有意义的,因为遇到非ASCII时会出错).对于对称性,允许类似的容易出错和无意义decode的unicode类型; 它将encodeASCII(如果unicode包含非ASCII,则出错),然后decode在请求的编解码器中.这是各种误解,错误等的根源.
在Python 3中,他们更好地分割了类型:
str是的文本类型,并且只具有一个encode方法(从逻辑字符转换为所述字符的特定二进制编码)bytes(和其他bytes类似的类型)表示二进制数据,并且只有一个decode方法(从特定的二进制编码转换为逻辑字符)你的代码要求"纯文本"类型支持decode(二进制 - >文本),正如我所指出的,Py2允许这在有限的意义上,即使它通常是愚蠢的.Py3没有; decode- 逻辑文本到逻辑文本是没有意义的,为了避免无声的错误行为,Py3不提供无效的方法(Py2将根据unicode对象的内容工作,然后在错误时失败;你会认为你的代码是非 - 英语友好,如果你真的使用它与非英语文本,它会中断).
csv如果您需要完全可移植性,编写必须处理非ASCII类型的代码并非易事.这是问题所在:
str(面向字节)编码作为一些不包含嵌入式NULs的编码,而不是unicode.注意: unicode如果它只包含返回的编码中的文本,则巧合工作sys.getdefaultencoding(),因为csv使用该值进行静默编码,通常ascii由site模块在启动时配置sys.setdefaultencoding; 在调用之后site删除sys.setdefaultencoding,你不应该自己调整它; 当输入有任何不适合语言环境编码的时候,它会csv从强制转换unicode回来时中断str.这不仅仅是系统区域设置的问题; 在我的系统上,使用LANG=en_US.latin-1或者LANG=en_US.utf-8,Python仍然'ascii'以我的身份返回sys.getdefaultencoding().str(面向文本,相当于Py2的unicode)通常,对于非csv相关情况,我建议使用纯粹基于文本的类型io.open来获得Py2.7和Py3.x之间的完全兼容性(以及更好的性能/兼容性codecs.open).但是io.open(并且codecs.open就此而言)在文本模式下返回unicodePy2(csv除非它在默认编码中可以表示,否则不能使用,所以你认为它可以工作,直到你提供默认编码无法处理的东西),并且str在Py3(罚款); 在二进制模式下,它返回str上的Py2(罚款,如果没有内嵌NULS,虽然它不是解码你,所以你需要两个解码从str到unicode,然后编码从后unicode到utf-8 str),并bytes在PY3(需要被解码str) .它很丑.
我可以给出的最佳解决方案是使用io.open,但是在特定步骤生成的迭代器周围添加一个依赖于版本的包装器,以确保迭代器的输出处于给定Python版本的适当形式(在Py3 utf-8中str以Py2 编码str),您的一致行为(并将版本检查限制为每个文件执行固定次数,而不是每行一次):
import io
import sys
encodings = {'ukprocessed.csv': 'utf8',
'usprocessed.csv': 'utf8',
'uyprocessed.csv': 'latin1',
'arprocessed.csv': 'latin1'}
# io.open in text mode will return unicode on Py2, str on Py3, decoded appropriately
# newline='' prevents it from doing line ending conversions (which are csv's
# responsibility)
with io.open(filepath, encoding=encodings[filepath], newline='') as csvdata:
if sys.version_info[0] == 2:
# Lazily convert lines from unicode to utf-8 encoded str
csvdata = (line.encode('utf-8') for line in csvdata)
reader = csv.reader(csvdata)
if sys.version_info[0] == 2:
# Decode row values to unicode on Py2; they're already str in Py3
reader = ([x.decode('utf-8') for x in row] for row in reader)
for row in reader:
# operate on row containing native text types as values that can
# represent whole Unicode range (unicode on Py2, str on Py3)
...
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3014 次 |
| 最近记录: |