预处理csv.reader的一行

时间:2018-05-18 15:54:38

标签: python csv

我正在尝试使用csv.reader解析csv文件。但是,此文件中的某个字段未正确编码。它是用双引号括起来的字符串,但字符串中的双引号不会被转义。

id,name,score
1,"something" like this",20

由于只有这样的一个字段,我应该能够通过查找第一个和最后一个双引号并在它们之间转义任何双引号来更正此字段。有没有办法在csv.reader处理它之前预处理一行来实现这样的东西?

3 个答案:

答案 0 :(得分:4)

csv.reader将很乐意从任何迭代中读取行,包括生成器,因此我们可以使用生成器来执行引用转义。但我们还需要告诉csv.reader我们的escapechar

我已将一些测试数据作为字符串列表嵌入到此代码中,但您可以将打开的文件传递给fixlines生成器。

import csv 

data = '''\
id,name,score
1,"something" like this",20
2,"another thing" like that",30
'''.splitlines()

def fixlines(lines):
    for row in lines:
        try:
            first = row.index('"') + 1
            last = row.rindex('"')
        except ValueError:
            pass
        else:
            stuff = row[first:last].replace('"', '\\"')
            row = row[:first] + stuff + row[last:]
        yield row

reader = csv.reader(fixlines(data), escapechar='\\')
for row in reader:
    print(row)

<强>输出

['id', 'name', 'score']
['1', 'something" like this', '20']
['2', 'another thing" like that', '30']

此代码不会更改不包含双引号(如标题行)或一对双引号的行,但如果找到包含单个双引号的行,它可能无法完全按照您的要求进行更改引用。修复这是留给读者的练习。 ;)

但是,它确实正确处理了引用字符串中的逗号。

这也适用于csv.DictReader

reader = csv.DictReader(fixlines(data), escapechar='\\')
for row in reader:
    print(row)

<强>输出

OrderedDict([('id', '1'), ('name', 'something" like this'), ('score', '20')])
OrderedDict([('id', '2'), ('name', 'another thing" like that'), ('score', '30')])

答案 1 :(得分:0)

请参阅下文,其中test.csv是您的CSV文件:

import csv

with open('test.csv') as csvfile:
    readCSV = csv.reader(csvfile, delimiter=',', quotechar='\'')
    for row in readCSV:
        row[1] = str(row[1])[1:-1]
        print("{0} | {1} | {2}".format(row[0], row[1].replace('"', '\\"'), row[2]))

这给出了:

id | am | score
1 | something\" like this | 20
2 | hello\" world | 50

这是你在找什么?

答案 2 :(得分:0)

与其他答案类似,但您可以链接生成器并使用正则表达式处理行,因为它们被读入csv阅读器而不是将整个文件预处理到列表中。

import re
import csv
import io

csv_file = io.StringIO("""\
id,name,score
1,"something" like this",20
111,"something", comma'd, like this",202020""")

def requote_line(line):
    try:
        before, mid, after = re.match('(.*?")(.*)(".*)', line).groups()
        return before + mid.replace('"', '') + after
        # or `mid.replace('"', '""')` if you want to keep the quotes
    except AttributeError:
        return line

reader = csv.reader(requote_line(line) for line in csv_file)
table = list(reader)
for row in table:
    print(row)

跑步,打印

['id', 'name', 'score']
['1', 'something like this', '20']
['111', "something, comma'd, like this", '202020']