【问题标题】:Python UNICODE csv reader GZIPPED filePython UNICODE csv 阅读器 GZIPPED 文件
【发布时间】:2017-12-23 00:10:03
【问题描述】:

我已经阅读了所有与 unicode 阅读相关的主题,但我似乎无法让它发挥作用。

我正在尝试读取一个恰好有 utf-8 BOM 签名并且也是 utf-8 的 csv。

所以,打开文件后,使用 unicodecsv 库读取它,我尝试了不同的方法。

def _extract_gz(self):  # fd
    logging.info("Gz detected")
    self.fp = gzip.open(self.path)
    return unicodecsv.reader(self.path.read().decode('utf-8-sig').splitlines(), encoding='utf-8')

在第 226 行仍然失败。UnicodeEncodeError: 'ascii' codec can't encode character u'\xf1' in position 226: ordinal not in range(128)

也尝试过这种方法,但也失败了。

def _extract_gz(self):  # fd
    logging.info("Gz detected")
    self.fp = gzip.open(self.path)
    self.f = self.unicode_csv_reader()
    return self.f

def unicode_csv_reader(self):
    csv_reader = csv.reader(self.fp.read().decode('utf-8-sig').splitlines())
    for row in csv_reader:
        yield [cell.encode('utf-8', 'replace') for cell in row]

我做错了什么?

谢谢大家。

版本是Python 2.7.12

【问题讨论】:

  • 我知道 unicodecsv 必须是 bytearray。我也尝试过这种方法:code def _extract_gz(self): # fd logging.info("Gz detected") self.fp = gzip.open(self.path) self.f = unicodecsv.reader(bytearray(self. fp.read()) return self.f 似乎所有的格式都正确但是,一旦我执行 f.next() 读取标题,就会出现这个错误。TypeError: expected string or Unicode object, int found即使打印 type(f) 返回 unicodecsv.py2.UnicodeReader
  • 如果您使用 CSV 并且遇到 UTF 问题,最好放置 python-2 或 python-3 标签,因为我记得不同(和棘手)的行为差异。
  • 感谢@MariusSiuram 的回复,您指的是哪些标签?
  • 我指的是您问题中的 StackOverflow 标签。此外,您可以编辑(可以吗?)以指定您的确切 python 版本。
  • 已更新。谢谢!

标签: python python-2.7 csv unicode gzip


【解决方案1】:

内置的csv 模块不支持Unicode(假设是Python 2.x),但是有一个替代的unicodecsv 模块支持(你显然已经尝试过了,但没有成功)并且它应该相当简单:

import gzip
import unicodecsv as csv

def read_csv(filename, has_bom=True, **kwargs):
    with gzip.open(filename, "r") as f:
        if has_bom:
            f.seek(3)  # skip the BOM
        reader = csv.reader(f, **kwargs)
        for row in reader:
            yield row

for row in read_csv("path/to/your.csv.gz", delimiter=";"):  # encoding needed for BOM
    print(row)  # or do whatever you want with it

应该做的伎俩。

更新 - 上面的代码适用于您上传的文件并且不会引发任何错误(因为您的文件由半列分隔,我也添加了这一点),但是有unicodecsv 模块中的一个错误 - 在使用 BOM 解析文件时,它不会删除第一列名称周围的引号,因此我更新了代码以反映这一点。

在您上传的文件上运行它时,您会得到以下输出(YMMV,取决于您的控制台如何打印 unicode):

[u'Name', u'Ref', u'POS', u'POS', u'Status', u'City', u'']
[u'Hotel Flamero', u'3365', u'ES', u'0.27', u'No Change', u'Matalascañas', u'']

(最后一个空条目是由于您的 CSV 的最后一个条目为空)

UPDATE#2 - 手头没有 MySQL 实例,但您可以使用内存中的 SQLite DB 检查它是否可以正常解析:

import sqlite3
db = sqlite3.connect(":memory:")  # create an in-memory DB
c = db.cursor()
c.execute("CREATE TABLE test (Name TEXT, Ref TEXT, POS TEXT, Status TEXT, City TEXT)")

header = None
for row in read_csv("path/to/your.csv.gz", delimiter=";"):
    del row[-1]  # remove the last element as it's always empty
    if header is None:  # get the header first
        header = row
        continue
    query = u"INSERT INTO test ({}) VALUES ({})".format(
        u", ".join(header),
        u", ".join(u"'{}'".format(column) for column in row)  # quote each column entry
    )
    c.execute(query)

# now lets read our data from the DB
c.execute("SELECT * FROM test")
for row in c.fetchall():
    print(row)

打印愉快:

(u'Hotel Flamero', u'3365', u'ES', u'No Change', u'Matalascañas')

【讨论】:

  • 如果我这样做,我会得到 "new_row = str(row[0]).replace('"','').split(';') UnicodeEncodeError: 'ascii' codec can't在位置 224 编码字符 u'\xf1':序数不在范围内(128)“也许是当我转换为 str 以替换字符串中不需要的字符时? (假设 csv 包含带双引号的字符串,我想删除它们,它们看起来像 ['"name"', etc..]
  • @AlbertoC。 - 您可以发布您的 CSV 文件样本吗?这应该适用于任何带有 BOM 的普通 gzipped CSV(假设默认引号、分隔符等)。
  • @AlbertoC。 - 不要在这里发布,在某处上传几行的压缩版本,导致上述代码出现上述错误。
  • 这是我的代码中失败的地方(跳过标题,它在我发送给你的 test.csv 的第一行失败)。对于 f 中的行: print(row) new_row = str(row[0]).replace('"','').split(';') UnicodeEncodeError: 'ascii' codec can't encode character u'\xf1 ' 在第 48 位:序数不在范围内(128)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多