#!/usr/bin/perl -w # ============================================================================ # csvdiff.pl - compare two csv files, Copyrigth 2006 - Roland Schmitz # ============================================================================ # This is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public # License as published by the Free Software Foundation; either # version 2.1 of the License. # # This program is distributed because i hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # ============================================================================ # csvdiff is a Perl script to diff/compare two csv files with the possibility # to select the separator. Differences will be shown like: "Column XYZ in # record 999" is different. After this, the actual and the expected result for # this column will be shown. # ============================================================================ # Contact: r-sch AT users DOT sourceforge DOT net # ============================================================================ # - Version "first workin version" # - created: 2006-03-01 by Roland Schmitz # - Version 01.00 - created: 2006-04-01 by Roland Schmitz # - Version 01.01 - created: 2006-04-09 by Roland Schmitz # - Version xx.xx - created: xx.xx.xxxx by xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # changed: xx.xx.xxxx by xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # last change: xx.xx.xxxx by xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # ============================================================================ #perl csvdiff.pl -a act.csv -e exp.csv -s ";" -c col_names.csv -k "2" |more #perl -d:ptkdb csvdiff.pl -a act.csv -e exp.csv -s ";" -c col_names.csv -k "2" use strict; use warnings; use vars qw($opt_d $opt_D $opt_h $debug); use Getopt::Std; use Scalar::Util qw[ looks_like_number ]; use Data::Dumper; # ---------------------- # --- used variables --- # ---------------------- our ($opt_s, $opt_a, $opt_e, $opt_c, $opt_k, $opt_t, $opt_i, $opt_f, $opt_v); our ($opt_g); my ($s_exp_file, $s_act_file, $s_col_file); my $s_version = "1.3"; # Version von csvdiff my $s_use_key = 1; # Vergleich mit (=1) oder ohne (=0) Key my $s_key_num = 1; # Key numerisch (=1) oder String/Feldname (=0) my $s_key_cols = 0; # Welche Spalte enthaelt den "unique key", # Zaehlung beginnt bei 0 my $s_fadeout_cols = ""; # Welche Spate(n) sollen nicht mit verglichen werden my $s_joined_key = ""; # Alle Keys zu einem String zusammenfassen, # um diese dann als Schluessel der Hashs zu # verwenden my $s_separator = ','; # Feldtrenner my $s_sort_data = 0; # Dateien sortieren vor vergleich? my $s_ignore = 0; # Groß- Kleinschreibung beim Vergleich beachten (=0) # oder nicht (=1) my %h_key_act; # Hash der aktuellen Daten # Schluessel = Keyspalte aus csv Datei # Wert = Zeilennummer my %h_key_exp; # Hash der erwarteten Daten # Schluessel = Keyspalte aus csv Datei # Wert = Zeilennummer my %h_key_all; # Hash das alle vorkommenden Key's enthaelt # Wert = wie offt kommt der jeweilige Key # in beiden Dateien vor my @a_records=(); # Array das mehrfach verwendet wird, um einen # Record am Trenner in einzelne Felder # aufzuspalten my @a_key_cols=(); # Array in das die uebergebenen Keys aufgespalten # werden my @a_fadeout_cols=(); # Array in das die uebergebenen "Fadeout" Spalten # aufgespalten werden my @a_lines_act=(); # Array das alle Zeilen aus dem ACT-File aufnimmt my @a_lines_exp=(); # Array das alle Zeilen aus dem EXP-File aufnimmt my @a_lines_col=(); # Array das alle Zeilen aus dem COL-File aufnimmt # eigentlich unnoetig, da COL nur eine Zeile enthalten # darf, so sieht's aber "symetrischer" aus my @a_col_names=(); # Array das die Spaltennamen aufnimmt my $s_diff_counter=0; # Variable die die Anzahl der unterschiedlichen # Zeilen zaehlt my $coloured_output=0; # Soll der output diff aehnlich sein, aber mit Farbe? # some tmp variables used as counters, ... my $s_line_counter; # Zeilenzaehler, wird mehrfach verwendet my $s_field_counter; # Feldzaehler, wird mehrfach verwendet my ($s_trim, $s_zeile, $s_zeile_join, $s_i, $s_tmp_counter, $s_key, $s_diff); my ($s_col, $s_tmp_col, $s_tmp_var); my (@a_trim_act, @a_trim_exp); sub buggy { if($debug){ my $index=0; print STDERR "\n-------------------------\n"; foreach(@_){ $index++; if(!$_) { $_ = "" } if($index==1) { print STDERR "Package: " . $_ ."\n" } if($index==2) { print STDERR "Line: " . $_ ."\n" } if($index==3) { print STDERR "File: " . $_ ."\n" } if($index==4) { print STDERR "Comment: " . $_ ."\n" } } print "-------------------------\n"; } } sub usage { # print "@_\n"; print "Usage: $0\n"; print " Parameters: -e Expected Result\n"; print " -a Actual Result\n"; print " -c Columnames in csv format (in only one Line!), optional\n"; print " -s Fieldseparator, optional (default=,)\n"; print " -h Help, optional\n"; print " -D Debug, optional\n"; print " -d coloured Output like diff\n"; print " -k Keycolumn(s), optional\n"; print " -t Trim space's, optional\n"; print " -i Ignore-case, optional\n"; print " -f Fade-out column(s), optional\n"; print " -g Grade/sort data before comparision, this has only\n"; print " effect when there are no key columns\n"; print " -v Print csvdiff version and quit\n"; print "\n"; print "If your key consists of multiple fields/columns use for example\n"; print " -k \"1;4;2\" column one four and two are the unique key.\n"; print "Multiple keys has to be separated by the fieldseparator\n"; print "Column and record count starts with 1!\n"; print "\n"; print "\nExample: $0 -e abc.txt -a xyz.txt -s \"|\" -c col.txt -k \"2|5\"\n"; } # Führende nund nachlaufende Leerzeichen aus Strings oder Arrays entfernen # Bsp.: $string = trim($string); # @many = trim(@many); sub trim { &buggy(__LINE__, __FILE__, "Subroutine \"trim\" Anfang"); my @out = @_; for (@out) { s/^\s+//; s/\s+$//; } return wantarray ? @out : $out[0]; } sub cmp_data { my ($s_tmp_data1, $s_tmp_data2) = @_; &buggy(__LINE__, __FILE__, "Subroutine \"cmp_data\" s_tmp_data1=$s_tmp_data1 s_tmp_data2=$s_tmp_data2"); my $s_tmp_cmp_res=undef; if($s_ignore) { # Groß- Kleinschreibung ignorieren $s_tmp_data1 = lc($s_tmp_data1); $s_tmp_data2 = lc($s_tmp_data2); #$s_tmp_cmp_res = $s_tmp_data1 =~ /\A\Q$s_tmp_data2\E\z/ ? 0 : 1; if($s_tmp_data1 =~ /\A\Q$s_tmp_data2\E\z/) { $s_tmp_cmp_res = 0; } else { $s_tmp_cmp_res = 1; } } else { # Groß- Kleinschreibung beachten #$s_tmp_cmp_res = $s_tmp_data1 =~ /\A\Q$s_tmp_data2\E\z/ ? 0 : 1; if($s_tmp_data1 =~ /\A\Q$s_tmp_data2\E\z/) { $s_tmp_cmp_res = 0; } else { $s_tmp_cmp_res = 1; } } return $s_tmp_cmp_res; } sub compare_data_array { return $a <=> $b if(looks_like_number($a) and looks_like_number($b)); return lc $a cmp lc $b; } #X#X#X#X##X#X#X#X##X#X#X #X#X#X#X# MAIN #X#X#X#X# #X#X#X#X##X#X#X#X##X#X#X #getopts('hdsae') or die "Option not valid!\n"; getopts('hdDtivgf:s:a:e:c:k:') or die "One Option is not valid!\n"; # siehe http://www.interaktiv.net/shop-system-support/tutorials/perlgetopt.shtml # suehe http://www.cis.uni-muenchen.de/~hbosk/perl2_ws03/einlesen/optionen_einlesen.html if (defined $opt_h) { print "\nOnline Help\n"; usage; $opt_v=1; } if (defined $opt_v) { print "\nThis is version $s_version of csvdiff\n\n"; print "csvdiff homepage: http://csvdiff.sourceforge.net/\n"; print " Contact: r-sch\@users.sourceforge.net\n\n"; print "This software is licenced unter the terms of GPL 2, feel free\n"; print "to use, customise, ... it.\n"; print "If you implement new features, it will be fine if you contact me.\n"; print "In a later version there will be more help, sorry.\n"; exit; } if (defined $opt_k) { $s_key_cols=$opt_k; $s_use_key=1; } else { $s_key_cols=0; $s_use_key=0; } if (defined $opt_f) { $s_fadeout_cols=$opt_f; } if (defined $opt_s) { $s_separator=$opt_s; } else { $s_separator=","; } if (defined $opt_g) { $s_sort_data=$opt_g; } if (defined $opt_D) { $debug=1; } else { $debug=0; } if (defined $opt_d) { $coloured_output=1; } else { $coloured_output=0; } if (defined $opt_t) { $s_trim=1; } else { $s_trim=0; } if (defined $opt_i) { $s_ignore=1; } else { $s_ignore=0; } # ------------------------------------------------------------------------ # check actual result file if (defined $opt_a) { if (-f $opt_a) { if (-r $opt_a) { $s_act_file=$opt_a; } else { print STDERR "Actual Result is unreadable\n"; exit 1; } } else { print STDERR "Actual Result dosen't exist\n"; exit 1; } } else { print "Actual csv File is needed! ->Exit\n"; usage; exit; } # ------------------------------------------------------------------------ # check expected result file if (defined $opt_e) { if (-f $opt_e) { if (-r $opt_e) { $s_exp_file=$opt_e; } else { print STDERR "Expectet Result is unreadable\n"; exit 1; } } else { print STDERR "Expectet Result dosen't exist\n"; exit 1; } } else { print "Expected csv File is needed! -> Exit\n"; usage; exit; } # ------------------------------------------------------------------------ # check column names file if (defined $opt_c) { if (-f $opt_c) { if (-r $opt_c) { $s_col_file=$opt_c; } else { print STDERR "Columnames file is unreadable\n"; exit 1; } } else { print STDERR "Columnames file dosen't exist\n"; exit 1; } } # -------------------------------------------------- # --- read files into array, without empty lines --- # -------------------------------------------------- if($opt_f) { #Es sollen eine oder mehrere Spalten nicht zum Vergleichen berücksichtigt werden @a_fadeout_cols = split(/$s_separator/, $s_fadeout_cols); #die uebergebenen Spalten am # Trenner aufspalten } open( FILE_ACT, "<$s_act_file" ) or die "File $s_act_file could not be opend: $!"; while () { chomp $_; next unless $_; #Leerzeilen werden ignoriert if($opt_f) { @a_records=(); #Array leeren @a_records = split(/$s_separator/, $_); #Zeile am Trenner aufspalten foreach $s_col (@a_fadeout_cols) { $s_tmp_col=$s_col-1; #Pruefen ob der angegebene Key existiert if(exists $a_records[$s_tmp_col]) { $a_records[$s_tmp_col]="Fade out for comapring"; } else { print "The fadeout column: $s_col did not exist => exit 1\n"; exit 1; } } #print Dumper(@a_records); $s_zeile_join = join("$s_separator", @a_records); #Array wieder zum String # machen push(@a_lines_act, $s_zeile_join); #aktuelle Zeile ans Ende des Arrays haengen } else { push(@a_lines_act, $_); #aktuelle Zeile ans Ende des Arrays haengen } } #@a_lines_act = ; # komplette Datei in Array einlesen close( FILE_ACT ); #print Dumper(@a_lines_act); open( FILE_EXP, "<$s_exp_file" ) or die "File $s_exp_file could not be opend: $!"; while () { chomp $_; next unless $_; #Leerzeilen werden ignoriert if($opt_f) { @a_records=(); #Array leeren @a_records = split(/$s_separator/, $_); #Zeile am Trenner aufspalten foreach $s_col (@a_fadeout_cols) { $s_tmp_col=$s_col-1; #Pruefen ob der angegebene Key existiert if(exists $a_records[$s_tmp_col]) { $a_records[$s_tmp_col]="Fade out for comapring"; } else { print "The fadeoutcolumn: $s_col did not exist => exit 1\n"; exit 1; } } #print Dumper(@a_records); $s_zeile_join = join("$s_separator", @a_records); #Array wieder zum String # machen push(@a_lines_exp, $s_zeile_join); #aktuelle Zeile ans Ende des Arrays haengen } else { push(@a_lines_exp, $_); #aktuelle Zeile ans Ende des Arrays haengen } } #@a_lines_exp = ; # komplette Datei in Array einlesen close( FILE_EXP ); #print Dumper(@a_lines_exp); if($s_col_file) { open( FILE_COL, "<$s_col_file" ) or die "File $s_col_file could not be opend: $!"; @a_lines_col = ; # komplette Datei in Array einlesen close( FILE_COL ); if (scalar @a_lines_col > 1) { print "Your columnnames file has more than one line => exit 1\n"; exit 1; } chomp(@a_lines_col); @a_col_names = split(/$s_separator/, $a_lines_col[0]); #ganze Array Zeile am Trenner # aufspalten } chomp(@a_lines_act, @a_lines_exp); # --------------------- # --- trim space'es --- # --------------------- if($s_trim) { #ACT Daten trimmen $s_line_counter = 0; @a_records = (); foreach $s_zeile (@a_lines_act) { @a_records = split(/$s_separator/, $s_zeile); #ganze Array Zeile am Trenner # aufspalten @a_records = trim(@a_records); #Fuehrende und nachlaufende # Leerzeichen abschneiden #print Dumper(@a_records); $s_zeile_join = join("$s_separator", @a_records); #Array wieder zum String # machen $a_trim_act[$s_line_counter] = $s_zeile_join; #$a_lines_act[$s_line_counter] = $s_zeile_join; $s_line_counter++; } @a_lines_act=@a_trim_act; #EXP Daten trimmen $s_line_counter = 0; @a_records = (); foreach $s_zeile (@a_lines_exp) { @a_records = split(/$s_separator/, $s_zeile); #ganze Array Zeile am Trenner # aufspalten @a_records = trim(@a_records); #Fuehrende und nachlaufende # Leerzeichen abschneiden #print Dumper(@a_records); $s_zeile_join = join("$s_separator", @a_records); #Array wieder zum String # machen $a_trim_exp[$s_line_counter] = $s_zeile_join; $s_line_counter++; } @a_lines_exp=@a_trim_exp; } # ------------------------- # --- Vergleich mit Key --- # ------------------------- if($s_use_key) { # --------------------------------------------------- # --- fill/create hash with data form actual file --- # --------------------------------------------------- $s_line_counter = 0; @a_records = (); # Array leer machen #Hash fuer act-file erzeugen in dem dem Key die Zeilennummer zugeordnet wird foreach my $s_zeile (@a_lines_act) { @a_records = split(/$s_separator/, $s_zeile); #ganze Array Zeile am Trenner # aufspalten @a_key_cols = split(/$s_separator/, $s_key_cols); #die uebergebenen Keys am # Trenner aufspalten $s_joined_key = ""; #Schluessel fuer Hash aufbauen if(scalar @a_key_cols == 1) { #Der Key besteht nur aus einem Feld, die -1 ist noetig, da das erste Feld im # Array 0 ist, uebergeben wird aber eine 1 #Pruefen ob der angegebene Key existiert if(exists $a_records[($a_key_cols[0]-1)]) { if(defined $a_records[($a_key_cols[0]-1)]) { ; #Key existiert } else { print "The keycolumn: $a_key_cols[0] contains an undefind value => exit 1\n"; exit 1; } } else { print "The keycolumn: $a_key_cols[0] did not exist => exit 1\n"; exit 1; } $s_joined_key = $a_records[($a_key_cols[0]-1)] } else { #Der Key besteht aus mehreren Feldern my $s_tmp_counter = 0; foreach (@a_key_cols) { #Pruefen ob der angegebene Key existiert if(exists $a_records[($_-1)]) { if(defined $a_records[($_-1)]) { ; #Key existiert } else { print "The keycolumn: $_ contains an undefind value => exit 1\n"; exit 1; } } else { print "The keycolumn: $_ did not exist => exit 1\n"; exit 1; } #die -1 ist noetig, da das erste Feld im # Array 0 ist, uebergeben wird aber eine 1 if($s_tmp_counter == 0) { #Sonderbehandlung fuer ersten Key, damit der Trenner nur zwischen den # Keys steht, und nicht vor dem ersten $s_joined_key = $a_records[($_-1)]; } else { $s_joined_key = $s_joined_key . $s_separator . $a_records[($_-1)]; } $s_tmp_counter++; } } #Der Schluessel der eingefuegt werden soll existiert bereits im Hash if(defined $h_key_act{$s_joined_key}) { print "ERROR: Key \"$s_joined_key\" is not unique in act_file => exit 1!\n"; exit 1; } $h_key_act{$s_joined_key}=$s_line_counter; #Hash belegen $s_line_counter++; # Zeilennummer inkrementieren } #Hash der alle Keys enthaelt mit Anzahl des vorkommens als Wert # hier werden die Keys aus act reingeschrieben foreach my $s_key ( sort keys %h_key_act){ if(defined $h_key_all{$s_key}) { $h_key_all{$s_key}=$h_key_all{$s_key}+1; } else { $h_key_all{$s_key}=1; } } # ----------------------------------------------------- # --- fill/create hash with data form expected file --- # ----------------------------------------------------- $s_line_counter = 0; @a_records = (); # Array leer machen #Hash fuer exp-file erzeugen in dem dem Key die Zeilennummer zugeordnet wird foreach $s_zeile (@a_lines_exp) { @a_records = split(/$s_separator/, $s_zeile); #ganze Array Zeile am Trenner # aufspalten @a_key_cols = split(/$s_separator/, $s_key_cols); #die uebergebenen Keys am # Trenner aufspalten $s_joined_key = ""; #Schluessel fuer Hash aufbauen if(scalar @a_key_cols == 1) { #Der Key besteht nur aus einem Feld, die -1 ist noetig, da das erste Feld im # Array 0 ist, uebergeben wird aber eine 1 #Pruefen ob der angegebene Key existiert if(exists $a_records[($a_key_cols[0]-1)]) { if(defined $a_records[($a_key_cols[0]-1)]) { ; #Key existiert } else { print "The keycolumn: $a_key_cols[0] contains an undefind value => exit 1\n"; exit 1; } } else { print "The keycolumn: $a_key_cols[0] did not exist => exit 1\n"; exit 1; } $s_joined_key = $a_records[($a_key_cols[0]-1)] } else { #Der Key besteht aus mehreren Feldern $s_tmp_counter = 0; foreach (@a_key_cols) { #Pruefen ob der angegebene Key existiert if(exists $a_records[($_-1)]) { if(defined $a_records[($_-1)]) { ; #Key existiert } else { print "The keycolumn: $_ contains an undefind value => exit 1\n"; exit 1; } } else { print "The keycolumn: $_ did not exist => exit 1\n"; exit 1; } #die -1 ist noetig, da das erste Feld im # Array 0 ist, uebergeben wird aber eine 1 if($s_tmp_counter == 0) { #Sonderbehandlung fuer ersten Key, damit der Trenner nur zwischen den # Keys steht, und nicht vor dem ersten $s_joined_key = $a_records[($_-1)]; } else { $s_joined_key = $s_joined_key . $s_separator . $a_records[($_-1)]; } $s_tmp_counter++; } } #Der Schluessel der eingefuegt werden soll existiert bereits im Hash if(defined $h_key_exp{$s_joined_key}) { print "ERROR: Key \"$s_joined_key\" is not unique in exp_file!\n"; exit 1; } $h_key_exp{$s_joined_key}=$s_line_counter; #Hash belegen $s_line_counter++; # Zeilennummer inkrementieren } #Hash der alle Keys enthaelt mit Anzahl des vorkommens als Wert # hier werden die Keys aus exp reingeschrieben foreach $s_key ( sort keys %h_key_exp){ if(defined $h_key_all{$s_key}) { $h_key_all{$s_key}=$h_key_all{$s_key}+1; } else { $h_key_all{$s_key}=1; } } #print "ALL:\n"; #foreach my $s_key ( sort keys %h_key_all){ # print $s_key." = ".$h_key_all{$s_key}."\n"; #} # ------------------------ # --- comparing starts --- # ------------------------ $s_line_counter = 0; $s_diff_counter = 0; foreach $s_key ( sort keys %h_key_all){ # Der Vergleich erfolgt in der sortierten Reihenfolge der Keys! $s_line_counter++; # Zeilennummer inkrementieren if(defined $h_key_exp{$s_key} && not defined $h_key_act{$s_key}) { # Key ist nur in exp enthalten if($s_diff_counter > 0) { # Trennzeile ausgeben print "\n", '-' x 79, "\n\n"; } $s_diff_counter++; print "Key: \"$s_key\" exists only in expected result $s_exp_file\n"; print " Expected: $a_lines_exp[$h_key_exp{$s_key}]\n"; } elsif(not defined $h_key_exp{$s_key} && defined $h_key_act{$s_key}) { # Key ist nur in act enthalten if($s_diff_counter > 0) { # Trennzeile ausgeben print "\n", '-' x 79, "\n\n"; } $s_diff_counter++; print "Key: \"$s_key\" exists only in actual result $s_act_file\n"; print " Actual line $h_key_act{$s_key}: $a_lines_act[$h_key_act{$s_key}]\n"; } elsif(defined $h_key_exp{$s_key} && defined $h_key_act{$s_key}) { # Key ist in beiden Dateien enthalten my $s_act_line = $h_key_act{$s_key}; my $s_exp_line = $h_key_exp{$s_key}; $s_diff = cmp_data($a_lines_act[$s_act_line], $a_lines_exp[$s_exp_line]); if($s_diff) { # if($a_lines_act[$s_act_line] ne $a_lines_exp[$s_exp_line]) { # Die einzelnen Records (als ganzes) sind unterschiedlich if($s_diff_counter > 0) { # Trennzeile ausgeben print "\n", '-' x 79, "\n\n"; } $s_diff_counter++; print "Record with key \"$s_key\" is different:\n"; #Zeile in einzelne Felder aufspalten my @a_fields_act = split /$s_separator/, $a_lines_act[$s_act_line]; my @a_fields_exp = split /$s_separator/, $a_lines_exp[$s_exp_line]; if($coloured_output) { #Unterschiede werden diff-maessig angezeigt my $tmp_act_line = sprintf (" Actual line %03d >",$s_act_line +1); my $tmp_exp_line = sprintf (" Expected line %03d >",$s_exp_line +1); $s_field_counter = 0; while(defined $a_fields_act[$s_field_counter] && defined $a_fields_exp[$s_field_counter]) { # Lauf ueber alle Felder der Records, so sie existieren # if ($a_fields_act[$s_field_counter] ne $a_fields_exp[$s_field_counter]) { $s_diff = cmp_data($a_fields_act[$s_field_counter], $a_fields_exp[$s_field_counter]); if($s_diff) { # Das aktuelle Feld ist unterschiedlich $tmp_act_line .= "\033[31m$a_fields_act[$s_field_counter]\033[39m$s_separator"; $tmp_exp_line .= "\033[32m$a_fields_exp[$s_field_counter]\033[39m$s_separator"; } else { $tmp_act_line .= "$a_fields_act[$s_field_counter]$s_separator"; $tmp_exp_line .= "$a_fields_exp[$s_field_counter]$s_separator"; } $s_field_counter++; } $tmp_act_line .= "\n"; $tmp_exp_line .= "\n"; print $tmp_act_line; print $tmp_exp_line; } else { #Unterschiedliches Feld wird angezeigt printf (" Actual line %03d > $a_lines_act[$s_act_line] <\n",$s_act_line +1); printf (" Expected line %03d > $a_lines_exp[$s_exp_line] <\n",$s_exp_line +1); $s_field_counter = 0; while(defined $a_fields_act[$s_field_counter] && defined $a_fields_exp[$s_field_counter]) { # Lauf ueber alle Felder der Records, so sie existieren # if ($a_fields_act[$s_field_counter] ne $a_fields_exp[$s_field_counter]) { $s_diff = cmp_data($a_fields_act[$s_field_counter], $a_fields_exp[$s_field_counter]); if($s_diff) { # Das aktuelle Feld ist unterschiedlich # printf (" Difference in field no.: %02d - field name: $a_col_names[$s_field_counter]\n",$s_field_counter +1); printf (" Difference in field no.: %02d",$s_field_counter +1); if ($opt_c) { print " - field name: $a_col_names[$s_field_counter]"; } print "\n"; print " Actual > $a_fields_act[$s_field_counter] <\n"; print " Expected > $a_fields_exp[$s_field_counter] <\n"; } $s_field_counter++; } } } else { # Die einzelnen Records (als ganzes) sind gleich #if($s_diff_counter > 0) { # # Trennzeile ausgeben # print "\n", '-' x 79, "\n\n"; #} #$s_diff_counter++; #print "Record with key \"$s_key\" is idetical\n"; } } else { # Das duerfte eigentlich nie eintreten, koennte ggf. weggelassen werden, # und das letzte "elsif" zum "else" gemacht werden print "ERROR bei Key: $s_key aufgetreten\n"; exit 1; } } } # -------------------------- # --- Vergleich ohne Key --- # -------------------------- else { # --------------------------------- # - Daten vor vergleich sortieren - # --------------------------------- if($s_sort_data) { @a_lines_act = sort compare_data_array @a_lines_act; @a_lines_exp = sort compare_data_array @a_lines_exp; } for( $s_line_counter = 0; defined $a_lines_act[$s_line_counter] && defined $a_lines_exp[$s_line_counter]; $s_line_counter++) { # Lauf ueber alle Zeilen beider Datein, solange sie definiert sind if($a_lines_act[$s_line_counter] ne $a_lines_exp[$s_line_counter]) { # In dieser Zeile gibt's mindestens einen Unterschied if($s_line_counter > 0) { # Trennzeile ausgeben print "\n", '-' x 79, "\n"; } my @a_act_fields = split /$s_separator/, $a_lines_act[$s_line_counter]; # Zeile in einzelne Felder aufteilen my @a_exp_fields = split /$s_separator/, $a_lines_exp[$s_line_counter]; # Zeile in einzelne Felder aufteilen printf ("\nRecord no: %03d is different:\n", $s_line_counter+1); print " Actual line: $a_lines_act[$s_line_counter]\n"; print " Expected line: $a_lines_exp[$s_line_counter]\n"; $s_field_counter=0; while(defined $a_act_fields[$s_field_counter] && defined $a_exp_fields[$s_field_counter]){ if($a_act_fields[$s_field_counter] ne $a_exp_fields[$s_field_counter]) { #printf (" Difference in field no.: %02d - field name: $a_col_names[$s_field_counter]\n", $s_field_counter +1); printf (" Difference in field no.: %02d",$s_field_counter +1); if ($opt_c) { print " - field name: $a_col_names[$s_field_counter]"; } print "\n"; print " Actual : $a_act_fields[$s_field_counter]\n"; print " Expected: $a_exp_fields[$s_field_counter]\n"; } $s_field_counter++; } } #else { #print "Zeile: $s_line_counter gleich\n"; #} } if(scalar @a_lines_act > $s_line_counter) { # Ausgabe der Zeilen die nur in ACT enthalten sind print "\n", '=' x 79, "\n\n"; print "Folowing lines exists only in actual result $s_act_file:\n"; for $s_i ($s_line_counter .. (scalar @a_lines_act -1)) { print "\n", '-' x 79, "\n\n"; printf (" Actual $s_i line %03d : $a_lines_act[$s_i]\n",$s_i +1); } } if(scalar @a_lines_exp > $s_line_counter) { # Ausgabe der Zeilen die nur in ACT enthalten sind print "\n", '=' x 79, "\n\n"; print "Folowing lines exists only in expected result $s_exp_file:\n"; for $s_i ($s_line_counter .. (scalar @a_lines_exp -1)) { print "\n", '-' x 79, "\n\n"; printf (" Actual line %03d : $a_lines_exp[$s_i]\n",$s_i +1); } } }