2014-09-02 3 views
0

Есть два файла CSV Я хочу сравнить. Однако у них есть другой порядок заголовков и строк/значений.Как сортировать CSV-файл по заголовку?

Вот простой пример:

ВХОД FILE1:

NAME,AGE,BDAY 
ABC,1,090214 
DEF,1,122514 

ВХОД FILE2:

BDAY,NAME,AGE 
122514,DEF,1 
090214,ABC,1 

ВХОД file3:

BDAY,NAME,AGE 
122514,DEFG,1 
090214,ABC,1 

Diff FILE1 и FILE2

No diffs. 

Diff FILE1 и file3

Found diffs in FILE and FILE3. 

<Any format of diffs is okay.> 

Я могу легко создать PERL скрипт для этого, но прежде, чем я, кто-нибудь знает, если есть существующий скрипт/инструмент, который уже делает это?

Я попытался скопировать файлы из UNIX в Windows и отсортировать их с помощью Excel. Он работает хорошо, но у меня проблемы с сохранением.

У меня также есть googled, но я не могу найти ссылку для этого.

Спасибо за любые входные данные.

+0

Это немного неясно, что вы спрашиваете: как изменить порядок? как сортировать? укажите желаемый результат, чтобы сделать его понятным. Подсказка: 'awk' может выполнить задание, переключая столбцы. – fedorqui

+0

Вы можете изменить порядок столбцов с помощью AWK, но вам нужно будет указать порядок 'cat file1 | awk -F ',' 'BEGIN {OFS = ",";} {print $ 3, $ 1, $ 2}' ' –

+0

@ChrisDoyle да, хорошая точка.Обратите внимание, что нет необходимости в 'cat':' awk 'BEGIN {FS = OFS = ","} {print ...}' file' делает это. – fedorqui

ответ

2

Я думаю, вам нужно какое-то передовое сравнение (с необходимостью более глубокого анализа), поэтому использование реляционного подхода db может быть интересно. В этом отношении полезно использовать module DBD::CSV. Он позволяет писать инструкции SELECT, включая соединение между таблицами.

+0

круто! никогда не знал, что драйвер DBI для CSV-файлов существует! – Carlisle18

0

Нормализация данных

  1. Используйте Text::CSV, чтобы изменить порядок столбцов файла CSV.
  2. Затем вы можете использовать Perl ’ s sort или какую-либо другую утилиту для изменения порядка строк ваших файлов.

Это также использует Text::Wrap для отображения нормированные файлов в приятном формате:

use strict; 
use warnings; 
use autodie; 

# Setup fake data 
my @files; 
{ 
    local $/ = ''; # Paragraph mode 
    while (<DATA>) { 
     chomp; 
     my ($file, $data) = split "\n", $_, 2; 
     open my $fh, '>', $file; 
     print $fh $data, "\n"; 
     push @files, $file; 
    } 
} 

# Normalize Files by Column Order 
use Text::CSV; 

my $csv = Text::CSV->new({ binary => 1, eol => $/ }) 
    or die "Cannot use CSV: " . Text::CSV->error_diag(); 

for my $file (@files) { 
    local @ARGV = $file; 
    local $^I = '.bak'; 
    my @old_order; 
    my @new_order; 
    while (<>) { 
     if (!$csv->parse($_)) { 
      die "Bad parse $file, line $.: " . $csv->error_diag(); 
     } 

     my @columns = $csv->fields(); 

     if ($. == 1) { 
      @old_order = @columns; 
      @new_order = sort @columns; 
     } 

     my %hash; 
     @hash{@old_order} = @columns; 

     if (!$csv->combine(@hash{@new_order})) { 
      die "Bad combine $file, line $.: " . $csv->error_diag(); 
     } 

     print $csv->string(); 
    } 
    unlink "$file$^I"; # Optionally delete backup 
} 

# Normalize Files by Row Order 
for my $file (@files) { 
    my ($header, @data) = do { local @ARGV = $file; <> }; 
    open my $fh, '>', $file; 
    print $fh $header, sort @data; 
} 

# View Normalized Files 
use Text::Wrap; 
for my $file (@files) { 
    open my $fh, '<', $file; 
    print wrap(sprintf("%-12s", $file), ' ' x 12, <$fh>,), "\n"; 
} 

__DATA__ 
file1.csv 
NAME,AGE,BDAY 
ABC,1,090214 
DEF,1,122514 

file2.csv 
BDAY,NAME,AGE 
122514,DEF,1 
090214,ABC,1 

file3.csv 
BDAY,NAME,AGE 
122514,DEFG,1 
090214,ABC,1 

Выходы:

file1.csv AGE,BDAY,NAME 
      1,090214,ABC 
      1,122514,DEF 

file2.csv AGE,BDAY,NAME 
      1,090214,ABC 
      1,122514,DEF 

file3.csv AGE,BDAY,NAME 
      1,090214,ABC 
      1,122514,DEFG 
Смежные вопросы