Re: Finding the parent of a text in a file
by choroba (Cardinal) on Sep 04, 2015 at 14:42 UTC
|
You can transform the input lines into "full paths", i.e. include all the antecendents to each element. Then, you can just run standard diff (Algorithm::Diff) on the items:
#!/usr/bin/perl
use warnings;
use strict;
use Algorithm::Diff qw{ diff };
open my $F1, '<', '1.in' or die $!;
my @lines1 = <$F1>;
open my $F2, '<', '2.in' or die $!;
my @lines2 = <$F2>;
chomp @lines1;
chomp @lines2;
# Transform the input lines.
my @path = q();
my @indent = q();
for my $line (@lines1, @lines2) {
my ($this_indent, $key) = $line =~ /^( +)(.*)/;
if ($this_indent eq $indent[-1]) {
$path[-1] = $key
} else {
if ($this_indent le $indent[-1]) {
pop @indent, pop @path while $indent[-1] ge $this_indent;
}
push @path, $key;
push @indent, $this_indent;
}
$line = join '/', @path;
}
# Compare the lines.
my @diffs = diff(\@lines1, \@lines2);
for my $diff (@diffs) {
for my $line (@$diff) {
print "@$line\n";
}
}
| [reply] [d/l] |
|
| [reply] |
|
I ran it on the input you provided, I changed the 2nd file a bit more and got the following result:
- 5 /system/security/management-ip/protocol/shutdown
+ 5 /system/security/management-ip/protocol/reboot
- 7 /system/security/management-ip/protocol/entry 1
- 8 /system/security/management-ip/protocol/entry 1/snmp ok
+ 7 /system/security/management-ip/protocol/entry 2
+ 8 /system/security/management-ip/protocol/entry 2/snmp ok
| [reply] [d/l] |
|
|
|
Re: Finding the parent of a text in a file ( is_deeply )
by 1nickt (Canon) on Sep 04, 2015 at 12:27 UTC
|
You can use is_deeply if you put your data into hashes. I'm making some assumptions here because your post isn't complete (eg that 'entry 1' and 'snmp ok' are keys, not key-value pairs) ... but hopefully this helps.
#!/usr/bin/perl
use strict;
use warnings;
use Test::More tests => 1;
my ($href1, $href2) = get_data();
is_deeply( $href2, $href1, 'Hashref comparison' );
## Sub to fetch data below; add code to read files if needed
sub get_data {
my $href1 = {
system => {
security => {
management_ip => {
protocol => {
internal => {},
shutdown => {},
allow => {},
entry_1 => {
snmp_ok => 'foo',
},
exit => {},
},
},
},
},
};
my $href2 = {
system => {
security => {
management_ip => {
protocol => {
internal => {},
shutdown => {},
allow => {},
entry_1 => {
snmp_ok => 'bar',
},
exit => {},
},
},
},
},
};
return $href1, $href2;
}
__END__
Output:
$ perl 1140982.pl
1..1
not ok 1 - Hashref comparison
# Failed test 'Hashref comparison'
# at 1140982.pl line 8.
# Structures begin differing at:
# $got->{system}{security}{management_ip}{protocol}{entry_1}{
+snmp_ok} = 'bar'
# $expected->{system}{security}{management_ip}{protocol}{entry_1}{
+snmp_ok} = 'foo'
# Looks like you failed 1 test of 1.
$
The way forward always starts with a minimal test.
| [reply] [d/l] [select] |
|
Hey 1nickt,
I recently ran into an issue while updating a module where I needed the functionality of is_deeply(), but I didn't want any test modules in the code, and I didn't want to have to hijack the output with trickery.
I came across Data::Compare, which simply returns a true/false bool if the structs match. You may be interested to play with this module for this kind of non-test work.
-stevieb
| [reply] [d/l] [select] |
|
Thanks. Looks useful. I like Test::More because it's a core module, so every installation has it, and because it indicates where the data differs (begins to differ). Usually I use this type of comparison where if it fails it should be fatal, so I don't mind the output. I can see how Data::Compare would be a better choice if you wanted to continue anyway. Interestingly, the same author has Test::Differences, which goes in the other direction (is still a Test::, spits TAP to STDOUT, provides a comprehensive diff of the structures).
The way forward always starts with a minimal test.
| [reply] |
|
Thanks lnickt for your help.
This program indeed does work But the issue is I have 2 very huge files to compare and they can have any hierarchy apart from system/security/entry etc (thus I cannot hard code the keys/key-value in the program).
Also, In this case the difference was in the child of entry 1, similarly in my file the difference can be at the entry 229 (say) , then it would become hard for me to go back till parent and print the same.
| [reply] |
|
Hi ExperimentsWithPerl,
The data structures were only hard-coded in my example because it was an example. You would need to create the hashes on the fly from the files, and then compare them.
If you are wanting to know all the differences in the files, you could use Test::Differences::eq_or_diff_data(), but that still wouldn't print out just the hierarchy as you wish. For that, choroba's solution seems like it may be the way to go.
But any diff solution (Test::Differences, system diff, whatever) will specify the lines at which the structures differ, so if that's all you need to know it might not be necessary to make the fully qualified "paths" choroba suggested. (It would help if you provided a sample input file and an example of the actual output you'd like to see.)
The way forward always starts with a minimal test.
| [reply] |
|
Re: Finding the parent of a text in a file
by kroach (Pilgrim) on Sep 04, 2015 at 12:07 UTC
|
What code do you already have? What exact problem prevents you from completing this program? | [reply] |
Re: Finding the parent of a text in a file
by Anonymous Monk on Sep 04, 2015 at 17:15 UTC
|
Seems to do what you showed. If not, please say why and provide a more extensive test case.
#!/usr/bin/perl
# http://perlmonks.org/?node_id=1140982
use Algorithm::Diff qw(traverse_sequences);
use strict;
use warnings;
my $file1 = <<END;
system
security
management-ip
protocol
internal
shutdown
allow
entry 1
snmp ok
exit
END
my $file2 = <<END;
system
security
management-ip
protocol
internal
shutdown
allow
entry 1
snmp failed
exit
END
sub fullpath
{
my @full;
my @answer;
for my $line ( shift() =~ /.+\n/g )
{
$line =~ /^( *)/;
$#full = length($1) - 1; # truncate array
push @full, $line;
push @answer, join '', grep defined, @full;
}
return \@answer;
}
my $full1 = fullpath($file1);
my $full2 = fullpath($file2);
traverse_sequences( $full1, $full2,
{
DISCARD_A => sub {print $full1->[shift()], "\n"},
} );
| [reply] [d/l] |
|
thanks a lot Anonymous Monk.You are right, it works fine with the example I have given .
But suppose I add another line below "snmp ok" (at the same level) :-
ipaddress#1
Then the code is printing the hirarechy twice for me ..once till "snmp ok" and once till "ipaddress#1".
Second thing, I tried to open both the config files as a file handler (Becase in real world the files will be too huge to keep in the code) and tried to run the code (with minimal changes), the code didnt work .
| [reply] |
|
Ah, you changed your requirements.
You get what you ask for, we're not mindreaders. How are we supposed to figure out what you really want when you don't give examples?
You never did mention file sizes, did you?
| [reply] |
|
|
|
| [reply] |
|
|
|
|
|