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

Hello Monks, I am trying to read in a file, search for a hash, replace all the text within two hash keys, and then write the changed data back into the file. I wrote a function called truncateText() to that uses the hash keys as the key words for the beginning and end of the block I need. My function to parse text between two keywords works but I am having difficulty replacing the data in the file. I haven't written the code yet to write back into the file because the data wasn't getting replaced accurately. Thank you so much monks for your endless wisdom.

sub populateHash{ my $inputFile = 'input.txt'; my $fileContent = do { open(my $fileHandle, $inputFile ) or die "Could not open file +'$inputFile ' $!"; local $/; <$fileHandle>; }; my $hashData = truncateText($fileContent, "key1 => {", "key2 =>"); my $dataToReplace = truncateText($hashData, "END_SEARCH_PATHS", "E +ND_SEARCH_PATHS"); #Removes Comments works best if called multiple times $dataToReplace =~ s/\#.*//; $dataToReplace =~ s/\#.*//; $dataToReplace =~ s/\#.*//; $dataToReplace =~ s/\#.*//; #replacementData was gathered in another function and stored i +n a global variable $fileContent =~ s/$dataToReplace/$replacementData/g; print Dumper($fileContent); } sub truncateText{ #Truncates text by removing everything before and and after the pa +ssed in variables my($text, $beginString, $endString) = @_; my $truncatedText; if($text =~ /\Q$beginString\E(.*?)\Q$endString\E/s){ $truncatedText = $1; #print $truncatedText; } return $truncatedText; }
  • Comment on Replacing a block of text inside two keys with another block of text
  • Download Code

Replies are listed 'Best First'.
Re: Replacing a block of text inside two keys with another block of text
by GrandFather (Saint) on Apr 24, 2017 at 21:32 UTC

    What does your input data look like? Show us a sample of the file you are processing. How confident are you that the structure of the "hash" you are editing won't change? If the file is written by Perl there is a fair chance that you can't depend on the order of the elements.

    Perhaps the more important question: what is the problem you are trying to solve? It is likely there is a better solution than a poor man's parse and edit of a text representation of a data structure.

    Premature optimization is the root of all job security

      I'm not sure how to modify the file since I am unable to load the file in and access the hash. If there is another solution I will be more than happy to implement it.

      #what replacement data looks like "new/path/desired/data" "new/path/desired/data" "new/path/desired/data"
      #data looks kinda like this key1 => { #some data i don't need #more data i don't need <<'END_SEARCHPATHS', #block of data I want to replace "some/path/to/some/file" "some/path/to/some/file" "some/path/to/some/file" "some/path/to/some/file" "some/path/to/some/file" "some/path/to/some/file" END_SEARCH_PATHS } key2 => { <<'END_SEARCHPATHS', #another block of data to replace "another/path/to/some/file" "another/path/to/some/file" "another/path/to/some/file" "another/path/to/some/file" END_SEARCH_PATHS }
        Filtering a dumped hash like this will not work reliably.

        Read the file in with do and filter the desired hash keys with a grep

        if this is not possible because of size or because order matters (i.e. wrong data format) consider using another data format!

        Probably best a SQL DB

        Cheers Rolf
        (addicted to the Perl Programming Language and ☆☆☆☆ :)
        Je suis Charlie!

        Your "sample data" sometimes omits the underscore in SEARCH_PATHS. If your real data does that, maybe that's one of your problems? If it doesn't, please stop giving us sample data that isn't representative.
Re: Replacing a block of text inside two keys with another block of text
by huck (Prior) on Apr 24, 2017 at 22:51 UTC

    When you run $dataToReplace =~ s/\#.*//; you are changing the $dataToReplace so that it no longer matches what is in $fileContent so nothing matches in the replace.

    use strict; use warnings; use Data::Dumper; my $replacementData=<<'REPDATA' "new/path/desired/data" "new/path/desired/data" "new/path/desired/data" REPDATA ; populateHash(); sub populateHash{ my $fileContent; if (0){ my $inputFile = 'input.txt'; $fileContent = do { open(my $fileHandle, $inputFile ) or die "Could not open file +'$inputFile ' $!"; local $/; <$fileHandle>; }; } else { $fileContent = do { local $/;<DATA>;};} my $hashData = truncateText($fileContent, "key1 => {", "key2 =>"); print 'hashdata:'.$hashData."\n\n"; # notice change to first END_SEARCHPATHS to match your sample data my $dataToReplace = truncateText($hashData, "END_SEARCHPATHS", "EN +D_SEARCH_PATHS"); print 'torep1:'.$dataToReplace."\n\n"; #Removes Comments works best if called multiple times # $dataToReplace =~ s/\#.*//smg; # $dataToReplace =~ s/\#.*//; # $dataToReplace =~ s/\#.*//; # $dataToReplace =~ s/\#.*//; #print 'torep:2'.$dataToReplace."\n"; #replacementData was gathered in another function and stored i +n a global variable # notice addition of \n to replacement to put first on its own line $fileContent =~ s/\Q$dataToReplace\E/\n$replacementData/; print 'Res:'.$fileContent."\n"; # print Dumper($fileContent); } sub truncateText{ #Truncates text by removing everything before and and after the pa +ssed in variables my($text, $beginString, $endString) = @_; my $truncatedText; if($text =~ /\Q$beginString\E(.*?)\Q$endString\E/s){ $truncatedText = $1; #print $truncatedText; } return $truncatedText; } __DATA__ key1 => { #some data i don't need #more data i don't need <<'END_SEARCHPATHS', #block of data I want to replace "some/path/to/some/file" "some/path/to/some/file" "some/path/to/some/file" "some/path/to/some/file" "some/path/to/some/file" "some/path/to/some/file" END_SEARCH_PATHS } key2 => { <<'END_SEARCHPATHS', #another block of data to replace "another/path/to/some/file" "another/path/to/some/file" "another/path/to/some/file" "another/path/to/some/file" END_SEARCH_PATHS }
    Result
    hashdata: #some data i don't need #more data i don't need <<'END_SEARCHPATHS', #block of data I want to replace "some/path/to/some/file" "some/path/to/some/file" "some/path/to/some/file" "some/path/to/some/file" "some/path/to/some/file" "some/path/to/some/file" END_SEARCH_PATHS } torep1:', #block of data I want to replace "some/path/to/some/file" "some/path/to/some/file" "some/path/to/some/file" "some/path/to/some/file" "some/path/to/some/file" "some/path/to/some/file" Res:key1 => { #some data i don't need #more data i don't need <<'END_SEARCHPATHS "new/path/desired/data" "new/path/desired/data" "new/path/desired/data" END_SEARCH_PATHS } key2 => { <<'END_SEARCHPATHS', #another block of data to replace "another/path/to/some/file" "another/path/to/some/file" "another/path/to/some/file" "another/path/to/some/file" END_SEARCH_PATHS }

Re: Replacing a block of text inside two keys with another block of text
by LanX (Saint) on Apr 24, 2017 at 22:51 UTC

      its all for one project and I suck at perl regex thats why :)