2012-05-23 2 views
0

У меня есть скрипт Python, который генерирует CSV (данные анализируются с веб-сайта). Вот Exemple из файла CSV:Pythonic способ сравнить два файла CSV для отслеживания изменений

File1.csv

China;Beijing;Auralog Software Development (Deijing) Co. Ltd.;;; 
United Kingdom;Oxford;Azad University (Ir) In Oxford Ltd;;; 
Italy;Bari;Bari, The British School;;Yes; 
China;Beijing;Beijing Foreign Enterprise Service Group Co Ltd;;; 
China;Beijing;Beijing Ying Biao Human Resources Development Limited;;Yes; 
China;Beijing;BeiwaiOnline BFSU;;; 
Italy;Curno;Bergamo, Anderson House;;Yes; 

File2.csv

China;Beijing;Auralog Software Development (Deijing) Co. Ltd.;;; 
United Kingdom;Oxford;Azad University (Ir) In Oxford Ltd;;; 
Italy;Bari;Bari, The British School;;Yes; 
China;Beijing;Beijing Foreign Enterprise Service Group Co Ltd;;; 
China;Beijing;Beijing Ying Biao Human Resources Development Limited;;Yes; 
This;Is;A;New;Line;; 
Italy;Curno;Bergamo, Anderson House;;Yes; 

Как вы можете видеть,

Китай; Пекин; BeiwaiOnline BFSU ;;; ==> Эта строка из File1.csv больше не присутствует в File2.csv и Это: Is; A; New; Line ;; ==> Эта строка из File2.csv является новой (нет в File1.csv).

Я ищу способ сравнить эти два файла CSV (важно знать, что порядок строк не учитывается ... они не могут быть где угодно).

Что бы я хотел иметь, это сценарий, который может мне рассказать: - Одна новая строка: This; Is; A; New; Line ;; - Удаленная линия: Китай; Пекин; BeiwaiOnline BFSU ;;; И так далее ...!

Я пробовал, но без успеха:

#!/usr/bin/python 
# -*- coding: utf-8 -*- 

import csv 

f1 = file('now.csv', 'r') 
f2 = file('past.csv', 'r') 

c1 = csv.reader(f1) 
c2 = csv.reader(f2) 

now = [row for row in c2] 
past = [row for row in c1] 

for row in now: 
    #print row 
    lol = past.index(row) 
    print lol 

f1.close() 
f2.close() 

_csv.Error: new-line character seen in unquoted field - do you need to open the file in universal-newline mode? 

Любая идея наилучшим образом, чтобы продолжить? Большое спасибо заранее;)

EDIT:

import csv 

f1 = file('now.csv', 'r') 
f2 = file('past.csv', 'r') 

c1 = csv.reader(f1) 
c2 = csv.reader(f2) 

s1 = set(c1) 
s2 = set(c2) 

lol = s1 - s2 
print type(lol) 
print lol 

Это кажется хорошей идеей, но:

Traceback (most recent call last): 
    File "compare.py", line 20, in <module> 
    s1 = set(c1) 
TypeError: unhashable type: 'list' 

EDIT 2 (Пожалуйста, не заботиться о том, что выше): * с вашей помощью, вот сценарий я пишу: *

#!/usr/bin/python 
# -*- coding: utf-8 -*- 
import os 
import csv 


### COMPARISON THING ### 
x=0 

fichiers = os.listdir('/me/CSV') 
for fichier in fichiers: 
    if '.csv' in fichier: 
     print('%s -----> %s' % (x,fichier)) 
     x=x+1 

choice = raw_input("Which file do you want to compare with the new output ? ->>>") 
past_file = fichiers[int(choice)] 
print 'We gonna compare %s to our output' % past_file 

s_now = frozenset(tuple(row) for row in csv.reader(open('/me/CSV/now.csv', 'r'), delimiter=';')) ## OUR OUTPUT 
s_past = frozenset(tuple(row) for row in csv.reader(open('/me/CSV/'+past_file, 'r'), delimiter=';')) ## CHOOSEN ONE 

added = [";".join(row) for row in s_now - s_past] # in "now" but not in "past" 
removed = [";".join(row) for row in s_past - s_now] # in "past" but not in "now" 

c = csv.writer(open("CHANGELOG.csv", "a"),delimiter=";") 
line = ['AD'] 
for item_added in added: 
    line.append(item_added) 
    c.writerow(['AD',item_added]) 

line = ['RM'] 
for item_removed in removed: 
    line.append(item_removed) 
    c.writerow(line) 

Два вида ошибок:

File "programcompare.py", line 21, in <genexpr> 
    s_past = frozenset(tuple(row) for row in csv.reader(open('/me/CSV/'+past_file, 'r'), delimiter=';')) ## CHOOSEN ONE 
_csv.Error: line contains NULL byte 

или

File "programcompare.py", line 21, in <genexpr> 
    s_past = frozenset(tuple(row) for row in csv.reader(open('/me/CSV/'+past_file, 'r'), delimiter=';')) ## CHOOSEN ONE 
_csv.Error: newline inside string 

Он работал несколько минут назад, но я изменил файлы CSV для тестирования с различной DATAS и я здесь :-)

Извините, последний вопрос!

+0

Попробуйте [ 'difflib'] (http://docs.python.org/library/difflib.html). –

+0

Если вы заботитесь только о самих линиях (но не о своих полях), вам не нужно разбирать файлы CSV. Просто сравните строки. – betabandido

ответ

6

Если данные не непозволительно большой, загружая их в set (or frozenset) будет простой подход:

s_now = frozenset(tuple(row) for row in csv.reader(open('now.csv', 'r'), delimiter=';')) 
s_past = frozenset(tuple(row) for row in csv.reader(open('past.csv', 'r'), delimiter=';')) 

Чтобы получить список записей, которые были добавлены:

added = [";".join(row) for row in s_now - s_past] # in "now" but not in "past" 
# Or, simply "added = list(s_now - s_past)" to keep them as tuples. 

аналогичным образом, список удаленных записей:

removed = [";".join(row) for row in s_past - s_now] # in "past" but not in "now" 

Чтобы ответить на ваш обновленный вопрос о том, почему вы видите TypeError: unhashable type: 'list', csv возвращает каждую запись как list при повторении. lists не являются hashable и поэтому не могут быть вставлены в set.

Чтобы решить эту проблему, необходимо добавить list записей в tuple s перед добавлением к набору. В предыдущем разделе в моем ответе приведен пример того, как это можно сделать.


Чтобы устранить дополнительные ошибки, которые вы видите, они оба связаны с содержимым ваших CSV-файлов.

_csv.Error: символ новой строки в строку

Похоже, у вас есть кавычки (") где-то в данных, путает анализатор. Я недостаточно разбираюсь в модуле CSV, чтобы точно рассказать вам, что пошло не так, не заглядывая в ваши данные.

Я тем не менее удалось воспроизвести ошибку как таковую:

>>> [e for e in csv.reader(['hello;wo;"rld'], delimiter=";")] 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
_csv.Error: newline inside string 

В этом случае он может фиксируется инструктаж читателя не делать каких-либо специальную обработку с кавычками (см csv.QUOTE_NONE). (Обратите внимание, что это отключит обработку цитируемых данных, в котором разделители могут появиться в кавычках без строки раскалывается на отдельные записи.)

>>> [e for e in csv.reader(['hello;wo;"rld'], delimiter=";", quoting=csv.QUOTE_NONE)] 
[['hello', 'wo', '"rld']] 

_csv.Error: строка содержит NULL байт

Я предполагаю, что это может быть до кодирования ваших файлов CSV. Смотрите следующие вопросы:

+1

Спасибо Так много, вы просто РОКИ! Это работает как шарм;) Я с нетерпением жду такого решения более трех часов, вы экономите мою ночь;) –

+0

Добро пожаловать @Carto_. Рад, что смог помочь. –

+1

Я отредактировал свой вопрос, последний раз я клянусь;) –

2

Читайте файлы csv по строкам в наборах. Сравните наборы.

>>> s1 = set('''China;Beijing;Auralog Software Development (Deijing) Co. Ltd.;;; 
... United Kingdom;Oxford;Azad University (Ir) In Oxford Ltd;;; 
... Italy;Bari;Bari, The British School;;Yes; 
... China;Beijing;Beijing Foreign Enterprise Service Group Co Ltd;;; 
... China;Beijing;Beijing Ying Biao Human Resources Development Limited;;Yes; 
... China;Beijing;BeiwaiOnline BFSU;;; 
... Italy;Curno;Bergamo, Anderson House;;Yes;'''.split('\n')) 
>>> s2 = set('''China;Beijing;Auralog Software Development (Deijing) Co. Ltd.;;; 
... United Kingdom;Oxford;Azad University (Ir) In Oxford Ltd;;; 
... Italy;Bari;Bari, The British School;;Yes; 
... China;Beijing;Beijing Foreign Enterprise Service Group Co Ltd;;; 
... China;Beijing;Beijing Ying Biao Human Resources Development Limited;;Yes; 
... This;Is;A;New;Line;; 
... Italy;Curno;Bergamo, Anderson House;;Yes;'''.split('\n')) 
>>> s1 - s2 
set(['China;Beijing;BeiwaiOnline BFSU;;;']) 
>>> s2 - s1 
set(['This;Is;A;New;Line;;']) 
+1

избил меня до него, drat. –

+0

Ваше решение кажется совершенно идеальным!У меня есть только один вопрос: Когда я пытаюсь поставить содержимое в набор, это Дайте мне эту ошибку: csv_content = множество (прошлое) TypeError: unhashable типа: «список» Я отредактировал мой вопрос –

Смежные вопросы