让csv.reader知道何时到达最后一行
显然,在某些地方的CSV输出实现中,当最后一行的字段为空时,会把字段分隔符从右边截断,只在文件的最后一行发生这种情况。
下面是一个示例输入的CSV文件,其中字段'c'和'd'是可为空的:
a|b|c|d
1|2||
1|2|3|4
3|4||
2|3
在下面这样的脚本中,我怎么才能知道我是否在最后一行,以便我可以正确处理它呢?
import csv
reader = csv.reader(open('somefile.csv'), delimiter='|', quotechar=None)
header = reader.next()
for line_num, row in enumerate(reader):
assert len(row) == len(header)
....
7 个回答
3
如果你希望每一行都有固定数量的列,那你就需要做好防范,考虑到以下两种情况:
(1) 任何一行可能会短一些——比如说,某些写入工具(像 SQL Server 或 Query Analyzer,我记得没错的话)可能会随机省略掉结尾的空值;用户也可能会用文本编辑器修改文件,甚至留下空行。
(2) 任何一行可能会长一些——比如说,逗号没有正确地加引号。
你不需要使用什么复杂的技巧。只需要在读取每一行的时候,做一个简单的判断:
for row in csv.reader(...):
ncols = len(row)
if ncols != expected_cols:
appropriate_action()
6
我知道这个问题已经问过很久了,但我想出了一个不同的答案。这个 reader
对象在你遍历它的时候,已经会自动增加 line_num
这个属性。所以我一开始用 row_count
得到总行数,然后再把它和 line_num
进行比较。
import csv
def row_count(filename):
with open(filename) as in_file:
return sum(1 for _ in in_file)
in_filename = 'somefile.csv'
reader = csv.reader(open(in_filename), delimiter='|')
last_line_number = row_count(in_filename)
for row in reader:
if last_line_number == reader.line_num:
print "It is the last line: %s" % row
16
基本上,你只有在用完之后才知道自己已经用完了。所以你可以把 reader
这个迭代器包裹起来,比如这样:
def isLast(itr):
old = itr.next()
for new in itr:
yield False, old
old = new
yield True, old
然后把你的代码改成:
for line_num, (is_last, row) in enumerate(isLast(reader)):
if not is_last: assert len(row) == len(header)
等等。