名为Sample.csv的CSV测试文件包含:
Brand, Price, Weight, Type
brand1, 6.05, 3.2, orange
brand2, 8.05, 5.2, orange
brand3, 6.54, 4.2, orange
brand1, 6.05, 3.2, pear
brand2, 7.05, 3.6, pear
brand3, 7.45, 3.9, pear
brand1, 5.45, 2.7, apple
brand2, 6.05, 3.2, apple
brand3, 6.43, 3.5, apple
brand4, 7.05, 3.9, apple
brand1, 8.05, 4.2, plum
brand2, 3.05, 2.2, plum
我的代码是:
import csv
headers = ['Brand','Price','Type']
with open('sample.csv', newline='') as rf:
reader = csv.DictReader(rf, delimiter=',',fieldnames=headers)
with open('output.csv', 'w', newline='') as wf:
writer = csv.DictWriter(wf, delimiter=',', extrasaction='ignore', fieldnames=headers)
writer.writerow(dict((fn,fn) for fn in writer.fieldnames))
for row in reader:
print(row)
writer.writerow(row)
我只是想把Brand,Price,Type输入到输出文件中,但是我得到了:
Brand,Price,Type
Brand, Price, Weight
brand1, 6.05, 3.2
brand2, 8.05, 5.2
brand3, 6.54, 4.2
brand1, 6.05, 3.2
brand2, 7.05, 3.6
brand3, 7.45, 3.9
brand1, 5.45, 2.7
brand2, 6.05, 3.2
brand3, 6.43, 3.5
brand4, 7.05, 3.9
brand1, 8.05, 4.2
brand2, 3.05, 2.2
为什么我在输出中得到Weight字段,而不是Type字段?
请注意,为了调试,添加了一行writer.writerow(dict((fn,fn)for fn in writer.fieldnames)),从而优先打印出两次标题。
答案 0 :(得分:2)
您在Brand, Price, Weight
中输入了列名headers
的事实不会使DictReader
解析,只返回源文件中的列。它只会将文件中找到的列分配给这些键 - 实际上,您可以将它们命名为First, Second, Third
,结果将是相同的。
您有两种选择:
使用您有标题行的事实,让DictReader
根据它命名键,然后只写出你想要的那些:
import csv
headers = ['Brand', 'Price', 'Type']
with open('sample.csv') as rf:
reader = csv.DictReader(rf, delimiter=',', skipinitialspace=True)
with open('output.csv', 'w') as wf:
writer = csv.DictWriter(wf, delimiter=',', extrasaction='ignore', fieldnames=headers)
writer.writeheader()
for row in reader:
print(row)
writer.writerow(row)
明确说明源中的列是什么,并在输出中明确显示您想要的内容 - 使用两个列表:
import csv
present_headers = ['Brand', 'Price', 'Weight', 'Type']
desired_headers = ['Brand', 'Price', 'Type']
with open('sample.csv') as rf:
reader = csv.DictReader(rf, delimiter=',', fieldnames=present_headers, skipinitialspace=True)
with open('output.csv', 'w') as wf:
writer = csv.DictWriter(wf, delimiter=', ', extrasaction='ignore', fieldnames=desired_headers)
writer.writeheader()
next(reader, None) #to skip writing the header row from the source
for row in reader:
# print(row)
writer.writerow(row)
鉴于您的问题中的样本,两个选项都会产生相同的结果。
一些评论 - 问题中的示例在分页符和数据行中都有分隔符,
后跟空格。如果它确实存在(不是复制和粘贴错误),阅读器中的选项skipinitialspace=True
将摆脱它 - 否则它将成为列中数据的一部分。
另一个是没有必要手动构建DictWriter的标题行 - 这就是writerheader()
方法的用途。
最后,您可以在选项2中看到在写入数据之前有调用next(reader, None)
- 它的目的是让读者产生第一行,因为它现在只是一个正常(不是标题),我们不想在输出中复制它。
答案 1 :(得分:0)
使用Python 3.5.2,我能够完全复制您的问题,所以我认为这也是您的版本。
您的问题是DictReader对象需要与sample.csv
中的标头匹配,否则reader
将不包含正确的数据。由于len(headers)
与sample.csv
中的列数不匹配,因此DictReader会将第一个len(headers)
列映射到您的reader
键,这就是“类型”和“权重”的原因'output.csv
中相互映射。虽然您可以在代码中复制sample.csv
标头并分别区分DictReader和DictWriter的输入和输出标头,但我建议让CSV处理正确的标头映射。只需从DictReader实例化中删除fieldnames=headers
即可完成此操作。
现在你让DictReader使用sample.csv
标题作为键,你需要保持你的调试行作为永久固定(虽然内置的writer.writeheader()
更简洁变异)。另外,由于sample.csv
在每个值之前包含空格,因此除第一个之外的每个header
元素都需要有一个前导空格来匹配reader
中的键。
您的最终代码可能如下所示:
import csv
headers = ['Brand',' Price',' Type']
with open('sample.csv', newline='') as rf:
reader = csv.DictReader(rf, delimiter=',')
with open('output.csv', 'w', newline='') as wf:
writer = csv.DictWriter(wf, delimiter=',', extrasaction='ignore', fieldnames=headers)
writer.writeheader()
for row in reader:
print(row)
writer.writerow(row)