Я пытаюсь найти разницу в двух файлах, которые содержат записи ключ / значение, и вернуть то, что все ключи / значения добавлены или удалены.В настоящее время я использую linux diff
для нахождения разницы, но вполне естественно, что если значения порядков будут изменены, то это будет действительный diff, но я не хочу их перечислять, потому что для меня это недопустимый.
file1:
key1 kamal1.google.com kamal2.google.com kamal3.google.com
key2 kamal4.google.com
file2:
key1 kamal1.google.com kamal6.google.com kamal3.google.com
key3 kamal4.google.com
Что мне нужно:
- Показать
deleted key2 with values kamal4.google.com
, added key3 with kamal4.google.com
, deleted kamal2.google.com from key1
, added kamal6.google.com to key1
- Сообщение является репрезентативным, мы можем изменить его на более значимое
Какой у меня подход:
- читать файлы и ставить в разные хеши
key1 => {kamal1.google.com => 1, ...}, key2 => {kamal4.google.com => 1}
.Я также взял массив в качестве хэша, чтобы мы могли эффективно выполнять различие. - Переходим по ключам обоих хэшей и определяем, существует ли он в каком хэше.
- Сделайте рекурсивный вызов, чтобы найти разностьв значениях (потому что это снова хеш)
Проблема с моим кодом:
- Не работает для вложения
- Потерянная дорожка родителя.
код:
my $file1 = 'file1';
my $file2 = 'file2';
my $old = hashifyFile($file1);
my $new = hashifyFile($file2);
my $result = {};
compareHashes($old , $new, $result);
print Dumper $result;
sub compareHashes {
my ($hash1, $hash2, $result) = @_;
for my $key (keys %$hash1, keys %$hash2) {
if (not exists $hash2->{$key}) {
push @{$result->{deleted}->{$key}}, keys %{$hash1->{$key}};
} elsif (not exists $hash1->{$key}) {
push @{$result->{added}->{$key}}, keys %{$hash2->{$key}};
} elsif (ref $hash1->{$key} eq 'HASH' or ref $hash2->{$key} eq 'HASH' ) {
compareHashes($hash1->{$key}, $hash2->{$key}, $result);
}
}
}
# helper functions
sub trim {
my $val = shift;
$val =~ s/^\s*|\s*$//g;
return $val;
}
sub hashifyFile {
my $file = shift;
my $contents = {};
open my $file_fh, '<', $file or die "couldn't open $file $!";
my ($key, @val);
while (my $line = <$file_fh>) {
# skip blank lines and comments
next if $line =~ /^\s*$/;
next if $line =~ /^#/;
# print "$. $line";
# if line starts with a word, means its "key values"
# if it starts with multiple spaces assuming minimum 4, seems values for the previous key
if ($line =~ /^\w/) {
($key, @val) = split /\s+|=/, $line;
} elsif ($line =~ /^\s{4,}\w/) {
push @val, split /\s+/, $line;
}
my %temp_hash;
for (@val) {
# next unless $_;
$temp_hash{trim($_)} = 1 if trim($_);
}
$key = trim($key);
$contents->{$key} = \%temp_hash if defined $key;
}
close $file_fh;
return $contents;
}