rv799cv has asked for the wisdom of the Perl Monks concerning the following question:

Hello All,

Gabor Azabo re-directed me to this site and I hope someone can give me a guide and clue.

I have wrote a Perl script to update about 1200 files for searching and replacing.

I have used a array of hashes like my

@myHashArray = ( {toFind => '<Image Name="Logo"> <Source>Embedded</Sou +rce>', toReplace => '<Image Name="Logo"><Source>E +xternal</Source>' }); Then I use this statement to find and replace the file. $data =~ s/$_->{toFind}/$_->{toReplace}/g foreach (@myHashArray);

Everything is working great and I am creating a log file (name of files I have changed) but I like also to get the values I have changed in that document. I want to get the value of /$_->{toFind}/ and toReplace in a log file too. Currently my log file is something like:

01- FirstFile.xml

02- SecondFile.xml

But want to have something like

01- FirstFile.xml

a. Original line: <Image

Name="Logo"><Source>Embedded</Source>

b. Replace with: <Image Name="Logo"><Source>External</Source>

And so on...

Replies are listed 'Best First'.
Re: array of hashes help
by rjt (Curate) on Apr 23, 2014 at 21:13 UTC

    If I understand you correctly, you just want the contents of toFind and the contents of toReplace in the same log file, right? Would this work?

     $data =~ s/$_->{toFind}/Original line: $_->{toFind}\n Replace with: $_->{toReplace}\n/g foreach (@myHashArray);

    But I confess I really don't know what you're doing or why you're doing it. Perhaps most importantly, you seem to make a distinction between "about 1200 files", and "a log file", but the code you have shown has no evidence of that (or, indeed, output of any kind). The $data =~ ... bit looks like it might be the original text replacement, but then where is the log file? Or is there another explanation entirely?

    use strict; use warnings; omitted for brevity.

      thanks you so much for your input and quick response

      Here I go through a loop of files and after reading files into $data I find and replace them using the write_file

      $data =~ s/$_->{toFind}/$_->{toReplace}/g foreach (@myHashArray); write_file($File::Find::name, $data); print LOGFILE "$counter $File::Find::name\n"; print LOGFILE "\t Original line: HERE WOULD BE MY ORIGINAL + LINE\n"; print LOGFILE "\t Replaced Line: HERE WOULD BE THE NEW LIN +E\n"; print "$counter $File::Find::name\n";

        Ok, that helps. If your files are indeed line-based (i.e., your patterns do not span multiple lines), then I suggest processing them line-by-line:

        use File::Slurp; my @myHashArray = ( { toFind => qr/(?i)foo/, toReplace => 'bar' } ); my $counter = 0; my $name = 'data_file'; # $File::Find::name for my $line (read_file('data_file', chomp => 1)) { $counter++; my $orig_line = $line; $line =~ s/$_->{toFind}/$_->{toReplace}/g for @myHashArray; next if $line eq $orig_line; print "LOG: $counter $name\n"; print "LOG: \t Original line: $orig_line\n"; print "LOG: \t Replaced line: $line\n"; }

        Here I've replaced LOGFILE with a LOG: prefix for ease of testing, and eliminated the reliance on File::Find for the same reason.

        With the following data_file:

        Foolius Caesar Footholomew Cubbins No changes here Just another barrage of text

        I get the following output:

        LOG: 1 data_file LOG: Original line: Foolius Caesar LOG: Replaced line: barlius Caesar LOG: 2 data_file LOG: Original line: Footholomew Cubbins LOG: Replaced line: bartholomew Cubbins

        Does that help?

        use strict; use warnings; omitted for brevity.
Re: array of hashes help
by Fessenden (Initiate) on Apr 23, 2014 at 23:23 UTC
    Could you just use regex variable capture? Enclose the toFind and toReplace with parentheses, like:
    $data =~ s/($_->{toFind})/($_->{toReplace})/g foreach (@myHashArray);
    And access them to print out to your log with $1 and $2?