【问题标题】:Python process a csv file to remove unicode characters greater than 3 bytesPython处理一个csv文件以删除大于3个字节的unicode字符
【发布时间】:2014-10-11 07:18:08
【问题描述】:

我正在使用 Python 2.7.5 并尝试获取现有的 CSV 文件并对其进行处理以删除大于 3 个字节的 unicode 字符。 (将此发送给 Mechanical Turk,这是亚马逊的限制。)

我尝试在这个问题 (How to filter (or replace) unicode characters that would take more than 3 bytes in UTF-8?) 中使用最高(惊人的)答案。我假设我可以逐行遍历 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 ,但我一直收到同样的错误。

【问题讨论】:

  • 向我们展示一些示例输入。

标签: python csv unicode


【解决方案1】:

您的输入仍然是编码数据,而不是 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() 函数生成所有行。

【讨论】:

  • 太棒了;一旦我用 'latin1' 替换了第一个 'utf8' (我得到了一个 UnicodeDecodeError: [] invalid continuation byte 错误),它就完美地工作了。你的解释最终帮助我将幕后发生的事情联系起来。谢谢!
  • @JedChristiansen:如果您有 Latin-1 编码数据,那么您不能在 BMP 之外有代码点。您的所有值都限于 Unicode 标准的前 255 个字符。
  • @JedChristiansen:在这种情况下,您只是将 Latin-1 重新编码为 UTF-8,只需使用 value.decode('latin1').encode('utf8') 就可以了。
  • 我认为问题在于我的源文件是乱七八糟的编码。我通过 API 从应用程序中获取几乎所有内容(HTML 标签,我认为是任何类型的编码)的内容。例如,通过上面的代码处理后 „ñone-click„ù 变为 _ãone-click_ã .
  • @JedChristiansen:垃圾进,垃圾出。尽可能早地为您从 API 获得的内容获取正确的编码。 Latin-1 恰好总是工作,因为您的输入字节总是在 0-255 范围内。当然,这并不意味着它是您数据的正确编码。
猜你喜欢
  • 1970-01-01
  • 2017-07-13
  • 1970-01-01
  • 1970-01-01
  • 2016-10-17
  • 1970-01-01
  • 2015-10-06
  • 2018-04-01
  • 1970-01-01
相关资源
最近更新 更多