Есть две проблемы: анализ формата данных и сравнение. Вы не можете просто сравнивать файлы по строкам, ваш файл имеет структуру, и вам нужно проанализировать его в структуре данных Perl.
sub parse_file {
my $file = shift;
open my $fh, '<', $file;
my $in_folder;
my %folders =();
while(<$fh>) {
# Entering a folder
if(/^Folder name (.*)\s*$/) {
$in_folder = $1;
}
# We're in a folder
elsif($in_folder) {
# Add a line to the folder actions
if(/^\s+(.*)\s*$/) {
push @{$folders{$in_folder}}, $1;
}
# We exited the folder but didn't enter another one
elsif(/^\S/) {
$in_folder = '';
}
}
}
return \%folders;
}
Это много дополнительного кода для написания и отладки. Если ваши файлы были сохранены в виде YAML, JSON или XML, вы можете использовать библиотеку для этого.
Я намеренно отказался от форматирования и просто сохранил имена папок. Это упрощает работу с данными и защищает остальную часть кода от изменений форматирования.
Теперь каждый файл представляет собой хэш имен папок, которые содержат список команд.
{
'A' => [
'cp A',
'cp B'
],
'B' => [
'cp D',
'cp F'
]
}
Теперь мы должны их сравнить. Алгоритм таков:
- Если папка находится в одном файле, выберите ее.
- Если папка находится в обоих файлах, укажите различия (если есть).
К счастью, у нас есть Array::Utils, чтобы выполнить все необходимые пересечения и разницы для нас. Используйте array_diff
, чтобы найти, какие папки находятся только в одном файле, и intersection
, чтобы найти те, которые находятся в обоих. Затем используйте array_diff
еще раз, чтобы найти различия.
sub compare_folders {
my($set1, $set2) = @_;
my @set1_names = keys %$set1;
my @set2_names = keys %$set2;
my %diffs;
# It's in one but not the other.
for my $name (array_diff @set1_names, @set2_names) {
$diffs{$name} = $set1->{$name} || $set2->{$name};
}
# It's in both.
for my $name (intersect @set1_names, @set2_names) {
# They're different
if(my @diff = array_diff(@{$set1->{$name}}, @{$set2->{$name}})) {
$diffs{$name} = \@diff;
}
}
return \%diffs;
}
И, наконец, нам нужно отобразить результаты. Поскольку я решил сделать данные обобщенными и отформатировать форматирование, нам нужно вернуть его обратно.
sub display_folder {
my($name, $values) = @_;
my $display = "Folder name $name\n";
for my $value (@$values) {
$display .= " $value\n"
}
return $display;
}
И все это вместе.
my @folders = map { parse_file($_) } @ARGV;
my $diff = compare_folders(@folders);
for my $name (keys %$diff) {
my $values = $diff->{$name};
print display_folder($name, $values);
}
Мой сценарий правильно печатает имя папки, но как только он встречается с тем же именем cp в двух файлах, он удаляет это имя cp для всех папок. В приведенном выше вопросе мой скрипт дает результат как имя папки C и имя папки D. Но я хочу, чтобы результат был таким же, как описано в вопросе. – Tej
Спасибо @Hunter McMillen за редактирование. – Tej
Пожалуйста, покажите нам, что вы уже сделали. –