使用Python比较两个.csv文件并输出结果

2 投票
4 回答
2548 浏览
提问于 2025-04-17 17:28

我刚开始学习编程,想写一个Python程序来比较两个.csv文件的特定列,检查哪些内容被添加、删除或修改了。这两个.csv文件的格式是一样的,列数也相同,使用BillingNumber作为关键字段:

BillingNumber,CustomerName,IsActive,IsCreditHold,IsPayScan,City,State
"2","CHARLIE RYAN","Yes","No","Yes","Reading","PA"
"3","INSURANCE BILLS","","","","",""
"4","AAA","","","","",""

我只需要比较第0、1、2和4列。我尝试了很多方法,但都没有成功。我知道可以用csv.DictReadercsv.reader把它们加载到字典里,但加载完之后我就不知道该怎么做了,不知道从哪里开始。

我之前尝试过这个:

import time
old_lines = set((line.strip() for line in open(r'Old/file1.csv', 'r+')))
file_new = open(r'New/file2.csv', 'r+')

choice = 0
choice = int( input('\nPlease choose your result format.\nEnter 1 for .txt, 2 for .csv or 3 for .json\n') )
time.sleep(1)
print(".")
time.sleep(1)
print("..")
time.sleep(1)
print("...")
time.sleep(1)
print("....")
time.sleep(1)
print('Done! Check "Different" folder for results.\n')
if choice == 1:
    file_diff = open(r'Different/diff.txt', 'w')
elif choice == 2:
    file_diff = open(r'Different/diff.csv', 'w')
elif choice == 3:
    file_diff = open(r'Different/diff.json', "w")
else: 
    print ("You MUST enter 1, 2 or 3")
    exit()

for line in file_new:
    if line.strip() not in old_lines:
        file_diff.write("** ERROR! Entry "+ line + "** Does not match previous file\n\n")
file_new.close()
file_diff.close()

这个方法不太好用,因为如果有多了一行,或者少了一行,它会把那行之后的所有内容都记录为不同。而且它比较的是整行,这不是我想要的。这个方法只是一个起点,虽然有点效果,但对我来说不够具体。我真的只是想找一个好的起点。谢谢!

4 个回答

0

看了你的评论:

我正在试着弄明白这件事。他们在公司发布了一个招聘新技术人员的职位,而他们要雇佣的人必须解决这个问题。

他们很可能在寻找一些命令行的技巧。类似于下面这个:

diff <(awk -F "\"*,\"*" '{print $1,$2,$3,$5}' csv1.csv) <(awk -F "\"*,\"*" '{print $1,$2,$3,$5}' csv2.csv)

这是一个可以在 bash 中使用的命令,利用 diff 工具来比较特定的列,这些列是通过 awk 选择出来的。

这显然不是基于 Python 的解决方案。不过,这个解决方案确实展示了简单的 Unix 工具的强大之处。

0

你需要自己写这个吗?如果这是一个编程练习,那就加油吧!不过,如果不是的话,可以找一个叫“diff”的工具,这个工具可能已经在你能接触到的某些软件里了。很多其他工具,比如文本编辑器(像vim、emacs和notepad++)以及版本控制系统(像subversion、mercurial和git)里都有这个功能。

我建议你使用这些已经成熟的工具,而不是自己重新发明轮子。git diff 是个非常强大的工具。

1

我觉得你使用csv模块的方向是对的。因为'BillingNumber'是一个唯一的标识符,所以我会为“旧”的账单文件创建一个字典,为“新”的账单文件再创建一个字典:

import csv

def make_billing_dict(csv_dict_reader):
    bdict = {}
    for entry in csv_dict_reader:
        key = entry['BillingNumber']
        bdict[key] = entry
    return bdict

with open('old.csv') as csv_file:
    old = csv.DictReader(csv_file)
    old_bills = make_billing_dict(old)

这样就得到了old_bills的数据结构:

{'2': {'BillingNumber': '2',
       'City': 'Reading',
       'CustomerName': 'CHARLIE RYAN',
       'IsActive': 'Yes',
       'IsCreditHold': 'No',
       'IsPayScan': 'Yes',
       'State': 'PA'},
 '3': {'BillingNumber': '3',
       'City': '',
       'CustomerName': 'INSURANCE BILLS',
       'IsActive': '',
       'IsCreditHold': '',
       'IsPayScan': '',
       'State': ''},
 '4': {'BillingNumber': '4',
       'City': '',
       'CustomerName': 'AAA',
       'IsActive': '',
       'IsCreditHold': '',
       'IsPayScan': '',
       'State': ''}}

一旦你为“新”的账单文件创建了相同的数据结构,你就可以很容易地找到它们之间的不同之处:

# Keys that are in old_bills, but not new_bills
print set(old_bills.keys()) - set(new_bills.keys())

# Keys that are in new_bills, but not old_bills
print set(new_bills.keys()) - set(old_bills.keys())

# Compare columns for same billing records
# Will print True or False
print old_bills['2']['CustomerName'] == new_bills['2']['CustomerName']
print old_bills['2']['IsActive'] == new_bills['2']['IsActive']

显然,你不会为每一个比较写一个单独的打印语句。我只是演示如何使用这些数据结构来找出差异。接下来,你应该写一个函数,循环检查所有可能的BillingNumbers,看看旧的和新的之间有什么不同……不过这部分我就留给你自己去做了。

撰写回答