Как найти разницу в записи csv

Есть ли алгоритм или утилиты, похожие на diff, для поиска различий между двумя файлами csv? Пример:

file1
-------
key1,value1
key2,value2
key3,value3
key5,value5
key7,value7

file2
-------
key1,value1
key3,value3
key4,value4
key5,value5
key6,value6

С помощью этой утилиты, похожей на diff, она будет выводить 3 типа записей:

  1. Записи, которые существуют только в файле1 (операция набора файлов1 минус файл2)
  2. Записи, которые существуют только в файле2 (файл2 минус операция установки файла1)
  3. Записи, которые существуют как в файле1, так и в файле2 (операция набора пересечений)

person hendrasaputra    schedule 29.05.2009    source источник
comment
Не знаю, есть ли он, но написание такого инструмента на Perl занимает всего около 30 минут :)   -  person workmad3    schedule 29.05.2009


Ответы (8)


diff может делать то, что вы хотите..

diff file1.csv file2.csv --old-line-format="< %L" --new-line-format="> %L" --unchanged-line-format="= %L"
person Anon    schedule 29.05.2009
comment
Я думаю, что это действительно то, что я мог бы использовать, в одной команде я получил все различия. - person hendrasaputra; 30.05.2009
comment
Я бы добавил, что вы должны сначала отсортировать оба CSV-файла с помощью команды sort. Я бы также добавил, что это не на 100% надежно, если в вашем CSV есть многострочные строки, и в этом случае вам нужно будет правильно проанализировать файл с помощью Text::xSV, записать ключи в хэши и сравнить их с List::Util и /или Список::MoreUtil. - person jiggy; 01.06.2009

есть Algorith::Diff

person dsm    schedule 29.05.2009

Взгляните на http://sourceforge.net/projects/csvdiff/.

csvdiff — это Perl-скрипт для сравнения/различения двух CSV-файлов с возможностью выбора разделителя. Различия будут отображаться следующим образом: «Столбец XYZ в записи 999 отличается». После этого будет показан фактический и ожидаемый результат для этого столбца.

person max muster    schedule 23.07.2010

Для этого вы можете использовать команду unix 'join'. Он также доступен в Cygwin для Windows.

Пример:

$ join -t ',' -v 1 file1 file2
key2,value2
key7,value7
$ join -t ',' -v 2 file1 file2
key4,value4
key6,value6
$ join -t ',' file1 file2
key1,value1,value1
key3,value3,value3
key5,value5,value5
person JimG    schedule 29.05.2009
comment
Оба сломаются, если у вас есть запятая в кавычках в вашем CSV. - person hbn; 29.05.2009

DiffKit с открытым исходным кодом может сделать это:

www.diffkit.org

person Community    schedule 15.12.2010

Вы можете взглянуть на мой потоковый редактор FOSS CSV CSVfix, который делает то, что вы хотите, с помощью команда соединения - программирование не требуется.

person Community    schedule 29.05.2009

Вы можете использовать хэши в Perl. Прочитайте каждый файл в отдельный хэш, что-то вроде

my %File1 = ();
my %File2 = ();
# Filehandles FP1 and FP2 is opened for read
while (<FP1>) {
    if (/^([^,]+),(.+)$/) {
        my ($key, $value) = ($1, $2);
        $File1{$key} = $value;
    }
}
# Repeat for FP2

Чтобы распечатать результаты, вы можете просмотреть хэши и проверить, идентичны ли ключ/значение, отличается или отсутствует различными способами. Пример:

for my $key (keys %File1) {
    if (defined($File1{$key}) && defined($File2{$key}) {
        print("$key exists in both files\n");
    } elsif (defined($File1{$key})) {
        print("$key exists only in file1\n");
    }
}
# Repeat for %File2
person sunny256    schedule 29.05.2009

Как насчет примера с использованием SQLite?

DROP TABLE 'file1';
DROP TABLE 'file2';

CREATE TABLE 'file1' (
    key_field VARCHAR primary key,
    value_field VARCHAR
);

CREATE TABLE 'file2' (
    key_field VARCHAR primary key,
    value field VARCHAR
);


.bail off
.separator ,
.import file1.csv file1
.import file2.csv file2

.output stdout
.header on

SELECT col1 AS 'In file1.csv, not in file2.csv' FROM (
    SELECT file1.key_field AS col1,
           file2.key_field AS col2 
    FROM file1 LEFT OUTER JOIN file2
    ON file1.key_field == file2.key_field
) 
WHERE col2 IS NULL
;

SELECT col2 AS 'In file2.csv, not in file1.csv'FROM (
    SELECT file1.key_field AS col1,
           file2.key_field AS col2
    FROM file2 LEFT OUTER JOIN file1
    ON file2.key_field == file1.key_field
) WHERE col1 IS NULL
;

SELECT file1.key_field AS 'In both file1.csv and file2.csv'
    FROM file1 INNER JOIN file2
    WHERE file1.key_field == file2.key_field
;

Вот результат:

C:\Temp> sqlite3 test.db < t.sql
In file1.csv, not in file2.csv
key2
key7
In file2.csv, not in file1.csv
key4
key6
In both file1.csv and file2.csv
key1
key3
key5
person Sinan Ünür    schedule 29.05.2009