Python处理CSV文件以移除大于3字节的Unicode字符

3 投票
1 回答
4125 浏览
提问于 2025-04-18 17:39

我正在使用Python 2.7.5,想处理一个现有的CSV文件,目的是去掉那些超过3个字节的unicode字符。(因为我要把这个文件发送到Mechanical Turk,而这是亚马逊的限制。)

我尝试使用这个问题中最好的答案(如何过滤(或替换)超过3个字节的unicode字符?)。我想我可以逐行遍历CSV文件,遇到超过3个字节的unicode字符时,就用一个替代字符来替换它们。

# -*- coding: utf-8 -*-
import csv
import re

re_pattern = re.compile(u'[^\u0000-\uD7FF\uE000-\uFFFF]', re.UNICODE)
ifile  = open('sourcefile.csv', 'rU')
reader = csv.reader(ifile, dialect=csv.excel_tab)
ofile  = open('outputfile.csv', 'wb')
writer = csv.writer(ofile, delimiter=',', quotechar='"', quoting=csv.QUOTE_ALL)

#skip header row
next(reader, None)

for row in reader:
    writer.writerow([re_pattern.sub(u'\uFFFD', unicode(c).encode('utf8')) for c in row])

ifile.close()
ofile.close()

但是我现在遇到了这个错误:

UnicodeDecodeError: 'ascii' codec can't decode byte 0xea in position 264: ordinal not in range(128)

所以虽然我能正确遍历一些行,但一到那些奇怪的unicode字符就停下来了。

我真的很感激一些指点;我完全搞不清楚。我把'utf8'换成了'latin1',还把unicode(c).encode改成了unicode(c).decode,但还是一直出现同样的错误。

1 个回答

3

你的输入数据仍然是编码过的数据,而不是Unicode值。你需要先解码unicode值,但你没有指定要使用哪种编码。然后,你还需要再编码回编码值,以便写回输出的CSV文件:

writer.writerow([re_pattern.sub(u'\uFFFD', unicode(c, 'utf8')).encode('utf8')
                 for c in row])

你的错误来自于unicode(c)这个调用;如果没有明确指定使用的编码,Python会默认使用ASCII编码。

如果你把文件对象当作上下文管理器使用,就不需要手动关闭它们:

import csv
import re

re_pattern = re.compile(u'[^\u0000-\uD7FF\uE000-\uFFFF]', re.UNICODE)

def limit_to_BMP(value, patt=re_pattern):
    return patt.sub(u'\uFFFD', unicode(value, 'utf8')).encode('utf8')

with open('sourcefile.csv', 'rU') as ifile, open('outputfile.csv', 'wb') as ofile:
    reader = csv.reader(ifile, dialect=csv.excel_tab)
    writer = csv.writer(ofile, delimiter=',', quotechar='"', quoting=csv.QUOTE_ALL)
    next(reader, None)  # header is not added to output file
    writer.writerows(map(limit_to_BMP, row) for row in reader)

我把替换的操作移到了一个单独的函数里,并使用生成器表达式按需生成所有行,以便给writer.writerows()函数使用。

撰写回答