2011-03-11 149 views
11

所以我有兩個CSV文件,我試圖比較並獲得類似項目的結果。 第一個文件,hosts.csv如下所示:比較兩個CSV文件並搜索相似的項目

Path Filename Size Signature 
C:\  a.txt  14kb
D:\  b.txt  99kb 678910 
C:\  c.txt  44kb 111213 

第二個文件,masterlist.csv如下所示:

Filename Signature 
b.txt  678910 
x.txt  111213 
b.txt  777777 
c.txt  999999 

正如你所看到的行不匹配和masterlist .csv總是大於hosts.csv文件。我想要搜索的唯一部分是簽名部分。我知道這看起來是這樣的:

hosts[3] == masterlist[1] 

我在找,這將使我類似如下(基本hosts.csv文件與新的結果列)的解決方案:

Path Filename Size Signature RESULTS 
C:\  a.txt  14kbNOT FOUND in masterlist 
D:\  b.txt  99kb 678910  FOUND in masterlist (row 1) 
C:\  c.txt  44kb 111213  FOUND in masterlist (row 2) 

我搜索了這些帖子,發現類似於這個here,但我不太瞭解它,因爲我還在學習python。

編輯使用Python 2.6

回答

9

編輯:雖然我的解決方案正常工作,看看下面的Martijn的回答更高效的解決方案。

你可以找到Python CSV模塊here的文檔。

你要找什麼是這樣的:

import csv 

f1 = file('hosts.csv', 'r') 
f2 = file('masterlist.csv', 'r') 
f3 = file('results.csv', 'w') 

c1 = csv.reader(f1) 
c2 = csv.reader(f2) 
c3 = csv.writer(f3) 

masterlist = list(c2) 

for hosts_row in c1: 
    row = 1 
    found = False 
    for master_row in masterlist: 
     results_row = hosts_row 
     if hosts_row[3] == master_row[1]: 
      results_row.append('FOUND in master list (row ' + str(row) + ')') 
      found = True 
      break 
     row = row + 1 
    if not found: 
     results_row.append('NOT FOUND in master list') 
    c3.writerow(results_row) 

f1.close() 
f2.close() 
f3.close() 
+1

這很不錯。使用csv.DictReader可能會更清晰,因爲您可以用'master_row ['signature']'替換'master_row [1]'。 – chmullig 2011-03-11 04:50:38

+0

這將在每個結果後生成一個空行。 – serk 2011-03-11 05:17:36

+0

空行問題依賴於系統。如果你在每一個結果後都得到一個空行,用'f3 = file('results.csv','wb')替換'f3 = file('results.csv','w')'行' – srgerg 2011-03-11 05:36:04

4

Python的CSV和收藏模塊,具體OrderedDict,是真正有用的在這裏。你想使用OrderedDict來保存鍵的順序等。你不需要,但它很有用!

import csv 
from collections import OrderedDict 


signature_row_map = OrderedDict() 


with open('hosts.csv') as file_object: 
    for line in csv.DictReader(file_object, delimiter='\t'): 
     signature_row_map[line['Signature']] = {'line': line, 'found_at': None} 


with open('masterlist.csv') as file_object: 
    for i, line in enumerate(csv.DictReader(file_object, delimiter='\t'), 1): 
     if line['Signature'] in signature_row_map: 
      signature_row_map[line['Signature']]['found_at'] = i 


with open('newhosts.csv', 'w') as file_object: 
    fieldnames = ['Path', 'Filename', 'Size', 'Signature', 'RESULTS'] 
    writer = csv.DictWriter(file_object, fieldnames, delimiter='\t') 
    writer.writer.writerow(fieldnames) 
    for signature_info in signature_row_map.itervalues(): 
     result = '{0} FOUND in masterlist {1}' 
     # explicit check for sentinel 
     if signature_info['found_at'] is not None: 
      result = result.format('', '(row %s)' % signature_info['found_at']) 
     else: 
      result = result.format('NOT', '') 
     payload = signature_info['line'] 
     payload['RESULTS'] = result 

     writer.writerow(payload) 

下面是使用測試CSV文件的輸出:

Path Filename  Size Signature  RESULTS 
C:\  a.txt 14kbNOT FOUND in masterlist 
D:\  b.txt 99kb 678910 FOUND in masterlist (row 1) 
C:\  c.txt 44kb 111213 FOUND in masterlist (row 2) 

請原諒的錯位,他們是製表符分隔:)

+0

我得到一個ImportError:無法導入名稱OrderedDict。我正在使用Python 2.6和Python 3的可移植版本。OrderedDict僅特定於2.7? – serk 2011-03-11 05:17:15

+0

是的。您可以將OrderedDict更改爲dict()並且它可以正常工作。 – 2011-03-11 05:34:55

+0

您可以將2.7 OrderedDict恢復到2.6。該模塊可以在這裏找到:http://hg.python.org/cpython/file/291bc0097cc1/Lib/collections/__init__.py – 2011-03-11 05:38:25

0

csv模塊就派上用場了在解析的CSV文件。但爲了好玩,我只是將輸入分割爲空格來獲取數據。

只解析數據,爲masterlist.csv中的數據構建一個dict,簽名爲鍵,行號爲值。現在,對於hosts.csv的每一行,我們可以查詢dict,並確定masterlist.csv中是否存在相應的條目,如果是,那麼在哪一行。

#! /usr/bin/env python 

def read_data(filename): 
     input_source=open(filename,'r') 
     input_source.readline() 
     return [line.split() for line in input_source] 

if __name__=='__main__': 
     hosts=read_data('hosts.csv') 
     masterlist=read_data('masterlist.csv') 
     master=dict() 
     for index,data in enumerate(masterlist): 
       master[data[-1]]=index+1 
     for row in hosts: 
       try: 
         found="FOUND in masterlist (row %s)"%master[row[-1]] 
       except KeyError: 
         found="NOT FOUND in masterlist" 
       line=row+[found] 
       print "%s %s %s %s %s"%tuple(line) 
17

由srgerg的答案是非常低效的,因爲它運行在二次時間;這裏是一個線性時間溶液代替,使用Python 2.6兼容的語法:

import csv 

with open('masterlist.csv', 'rb') as master: 
    master_indices = dict((r[1], i) for i, r in enumerate(csv.reader(master))) 

with open('hosts.csv', 'rb') as hosts: 
    with open('results.csv', 'wb') as results:  
     reader = csv.reader(hosts) 
     writer = csv.writer(results) 

     writer.writerow(next(reader, []) + ['RESULTS']) 

     for row in reader: 
      index = master_indices.get(row[3]) 
      if index is not None: 
       message = 'FOUND in master list (row {})'.format(index) 
      else: 
       message = 'NOT FOUND in master list' 
      writer.writerow(row + [message]) 

這將產生一個字典,從masterlist.csv映射簽名行號第一。字典中的查找需要一定的時間,使得第hosts.csv行上的第二個循環與masterlist.csv中的行數無關。更不用說代碼更簡單了。

+0

我希望你不介意,但我編輯了你的答案的最後一行,包括該消息未被顯示在原始內容中。 – srgerg 2014-04-15 22:38:20

+0

謝謝!這是我的意圖,但我忘了。 – 2014-04-15 23:11:38

+0

該腳本連同示例輸入將給出錯誤:「IndexError:列表索引超出範圍」 – Chubaka 2014-07-16 00:22:18