2013-02-28 51 views
2

我在编程方面相当新,我正在编写一个python程序,它将根据特定列比较2个.csv文件并检查添加,删除和修改。该.csv文件都按以下格式,包含列相同数量,并使用BillingNumber为重点:将2个.csv文件与Python进行比较,然后输出结果

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() 

,因为如果有一个额外的线,或者缺少一个,它会记录该行不同的后一切它不能正常工作。它也比较了我不想做的整个行。这基本上只是一个起点,虽然它有效,但它不足以满足我的需求。我真的只是寻找一个开始的好地方。谢谢!

+0

这将是开始的地方http://docs.python.org/2/library/csv.html – danodonovan 2013-02-28 16:39:35

+2

所以这听起来像你正在尝试编写一个diff程序。这是一个相当深入的话题。尝试http://stackoverflow.com/questions/805626/diff-algorithm或http://stackoverflow.com/questions/5897983/diff-algorithm-implementation-in-python。 – Hoopdady 2013-02-28 16:39:42

+1

“我不确定将它们加载到内存后到底在哪里或如何启动”。这是有原因的。你没有严格描述你想要的东西。您说过要“按特定列比较2个.csv文件并检查添加,删除和修改”。正如Hoopdady所说,这个简单的陈述涵盖了很多。我会首先仔细地写下你想要检查的内容(比如:如果一列中有一个加法,另一列中有一个删除,那该怎么办)。一旦你足够好地提出你的问题,实现将变得更容易。 – Wilduck 2013-02-28 16:41:54

回答

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,并检查新旧版本之间的差异,但我会为您保留该部分。

0

你自己写这个吗?如果这是一个编程练习,给你所有的权力。否则,请查找名为“diff”的工具,该工具可能以您已有权访问的某种形式存在。它内置于许多其他工具中,如文本编辑器,如vim,emacs和notepad ++,以及版本控制系统,如subversion mercurial和git。

我建议你使用既定的主力而不是重新发明轮子。 git diff是一只野兽。

+0

这只是我想弄明白的。他们为工作中的新技术人员提供了一份工作清单,而他们将雇用的人员必须解决这个问题。我只是想看看我是否能够出于好奇而做到这一点,但在尝试了大约一周之后,我一直无法做到。运营技术部门的人说这应该很容易,但似乎比他原先所说的更深入。我有时会感到无聊,这是我尝试的事情,但现在我想看看它的工作。如果这取决于我,我只是将它们加载到Excel中并进行比较。 – user2120375 2013-02-28 17:02:07

+0

他们绝对不希望你从头开始构建一个工具。 – 2013-02-28 18:10:03

0

阅读您的评论:

这只是一些我试图弄清楚。他们为工作中的新技术人员提供了一份工作清单,而他们将雇用的人员必须解决这个问题。

他们很可能正在寻找一些命令行fu。一个类似于

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

的命令will work in bash,使用diff工具,比较某些列,selected using awk

这显然不是一个基于python的解决方案。但是,这个解决方案确实证明了简单的基于Unix的工具的强大功能。

+0

确实非常酷。当我运行它时效果很好,但它在打印差异之前在第一行放置了一些奇怪的数字:4965a4966,4967。此外,这是一个相当艰难的程序,用python编写,还是我只是在我的技能背后? – user2120375 2013-02-28 17:22:55

+0

用python替换'awk'的部分是相当容易的。但是,编写自己的'diff'工具可能会非常复杂。 Fortunatley,Python是“包含电池”,并且已经包含一个差异库:http://docs.python.org/2/library/difflib.html。该实现是在Python中,所以你可以看看你是否想重新实现它http://svn.python.org/projects/python/trunk/Lib/difflib.py – Wilduck 2013-02-28 17:26:45

+1

它听起来比它更容易。我明白我想要它做什么,但我还没弄清楚如何用python实现它。我会继续努力。感谢所有的答复。 – user2120375 2013-02-28 17:31:00

0

因为这些东西的要求有一个倾向,我认为这是值得把数据放入SQLite数据库。

作为检测一行是否被删除或只是新的逻辑可能会很难实现。

在下面我推测BillingNumber是id并且不会被改变。

import sqlite3 
con = sqlite3.connect(":memory:") 

cursor = con.cursor() 
columns = "BillingNumber,CustomerName,IsActive,IsCreditHold,IsPayScan,City,State" 
cursor.execute("CREATE TABLE left (%s);" % columns) 
cursor.execute("CREATE TABLE right (%s);" % columns) 

placeholders = ",".join("?" * len(columns.split(','))) 

import csv 
def reader(filename): 
    for (lineno, line) in enumerate(open(filename)): 
     if lineno > 0: # skip header 
      yield line 

def load_table(tablebname, filename): 
    for row in csv.reader(reader(filename)): 
     cursor.execute("INSERT INTO %s VALUES(%s);" % (tablebname, placeholders), row) 

load_table("left", "left.csv") 
load_table("right", "right.csv") 

if False: 
    print "LEFT" 
    for row in cursor.execute("SELECT * from left;"): 
     print row[0] 

     print "RIGHT" 
     for row in cursor.execute("SELECT * from right;"): 
      print row 

def dataset(tablename, columns): 
    for row in cursor.execute("SELECT * from %s;" % tablename): 
     yield tuple(row[x] for x in columns) 

# To use if raw data required.  
#left_dataset = dataset("left", [0,1,2,4]) 
#right_dataset = dataset("right", [0,1,2,4]) 

# COMPARE functions. 
def different_rows(): 
    q = """SELECT left.*, right.* 
    FROM left, right 
    WHERE left.BillingNumber = right.BillingNumber 
    AND (left.CustomerName != right.CustomerName OR 
      left.IsActive  != right.IsActive OR 
      left.IsPayScan != right.IsPayScan) 
      ; 
    """ 
    for row in cursor.execute(q): 
     print "DIFFERENCE", row 

def new_rows(): 
    q = """SELECT right.* 
    FROM right 
    WHERE right.BillingNumber NOT IN (SELECT BillingNumber FROM left) 
      ; 
    """ 
    for row in cursor.execute(q): 
     print "NEW", row 

different_rows() 
new_rows() 

的OP必须编写不同功能的数据,但我比较使用SQL可能更容易在整体上。

相关问题