Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

text file search and replace

by igotlongestname (Acolyte)
on Feb 19, 2008 at 18:12 UTC ( [id://668859]=perlquestion: print w/replies, xml ) Need Help??

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

Ingenious Perl Monks, I'm trying to search for the word "END" in a file (which occurs only once), then replace it with several lines of text. I am having trouble in doing this correctly. I tried reading and writing from the same file, but get incorrect results. I am slurping all of the data to be inserted instead of "END" into one scalar, then trying to add that in place. The code that I am currently using is here:
$COMPFILE = IO::File->new; #!!!!!!!!!!!!!!!!!!!!!!!!! SCALAR SLURP !!!!!!!!!!!!!!!!!!!!!!!! $comptmplt_file="comp_template.txt"; { local $/; open SLURP, $comptmplt_file or die "sudden death"; $comptmplt=<SLURP>; close SLURP or die "cannot close $comptmplt: $!"; } #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! $COMPFILE->open("+< comp_no_rods.txt" or die "Can't open"); print "$comptmplt"; until ($COMPFILE -> eof){ $compline = $COMPFILE->getline(); if ($compline=~ /END/){; $compline=~ s/END/$comptmplt/; print $COMPFILE "$compline"; } }
I think some error is occuring, because the text in the scalar replace variable has the word "END" in it as well, but the code doesn't get stuck in an infinite loop, it just adds some screwy lines along with the correct ones. I am sure I am doing this backwards and someone here has a better idea and I'm all for hearing it. Any further questions are welcomed as well. Thanks! Update: I figured it'd be easier if I posted what was in each file: The end of the file to be altered (note the "END" is what I want to change)
! ========================================================== TITLE T2 C1 2V-03-12100 9193 - 9406 EFPH. UTBR STEG NR 018 OPTION Burnup,Neu3,NoSearch,TTable,FlwTot,NoPowEnd PRINT KEYPAR INIT /sompath/dist-9193.dat=HIST SAVE /somepath/dist-9406.dat=POWER,HIST,TM,TIPNEU,PRMNEU,CRWDR, SAVE * PINPOW,PINBUR,PINLHR,PINFIM,PINDRY POWER 88.900 FLOW 7737.0 PRESS 70.000 CONROD ALL=100 BURNUP 213.0000, 1, EFPH, Straight-Euler END
The text to be inserted in place of the "END"
! ========================================================== TITLE T2 C1 2V-03-12100 BEGIN - FINISH EFPH. UTBR STEG NR 018 OPTION Burnup,Neu3,NoSearch,TTable,FlwTot,NoPowEnd PRINT KEYPAR INIT /somepath/dist-BEGIN.dat=HIST SAVE /somepath/dist-FINISH.dat=POWER,HIST,TM,TIPNEU,PRMNEU,CRWDR, SAVE * PINPOW,PINBUR,PINLHR,PINFIM,PINDRY POWER 100.0 FLOW 6500 PRESS 70.000 CONROD ALL=100 BURNUP 500.0000, 1, EFPH, Straight-Euler END
I will do this once, do some calculations, check to see if I have satisfied a criteria. If I haven't, I'll add more data to the file by changing the "END" in the exact same way above, with the file growing by another addition of data, then re-run a calculation. (Hopefully that makes sense). If you want to see the output I currently get, feel free to ask. Thanks again.

Replies are listed 'Best First'.
Re: text file search and replace
by jwkrahn (Abbot) on Feb 19, 2008 at 20:05 UTC
    • Put these two lines at the top of your program:

      use warnings;
      use strict;

    • open SLURP, $comptmplt_file or die "sudden death";

      Since you are using braces to limit the scope of local $/; you should probably also use a locally scoped filehandle.    You should include the $! variable in the error message so you know why open failed.

    • $COMPFILE->open("+< comp_no_rods.txt" or die "Can't open");

      Your die statement will never execute because the string "+< comp_no_rods.txt" is always true.    You need to move the closing parenthesis before  or die.    You should include the $! variable in the error message so you know why open failed.

    • print "$comptmplt";

      What's wrong with always quoting "$vars"?

    • until ($COMPFILE -> eof){
          $compline = $COMPFILE->getline();

      In Perl you almost never need to use eof.    That is usually written as:

      while ( my $compline = <$COMPFILE> ) {

    •     if ($compline=~ /END/){;
              $compline=~ s/END/$comptmplt/;

      There is no need to use the same regular expression twice, just once is enough:

          if ( $compline =~ s/END/$comptmplt/ ) {;

    • Your main problem is that when you open a file in read-write mode ("+<") and read a line the file pointer moves to the end of that line and anything printed at that point overwrites any data in the file.    If you want to edit the file "in place" you can use the in-place edit variable $^I:

      ( $^I, @ARGV ) = ( '.bak', 'comp_no_rods.txt' );
      while ( <> ) {
          s/END/$comptmplt/;
          print;
          }

Re: text file search and replace
by Narveson (Chaplain) on Feb 19, 2008 at 18:28 UTC

    Don't use the same filehandle for reading and writing. One solution is to write what you want to a temporary file, then when you're done you can rename the temporary file to the original name.

    Or try Tie::File.

      Your comment is something I had noticed, but was unsure what to do about. I had been working on this for several hours with no luck and came for help, but somehow your comment triggered a different path. I got something that does exactly what I want it to, which is attached below. As a secondary thought, I want to be a better Perl programmer, thus if anybody has any ideas that are clear ways to do it better, or poor ways of programming in my code, I'm all for hearing them. Thanks!
      $COMPFILE = IO::File->new; $TMP = IO::File->new; $COMPTMPLT= IO::File->new; $COMPFILE->open("< comp_no_rods.txt" or die "Can't open"); $COMPTMPLT->open("< comp_template.txt" or die "Can't open comp_templat +e"); $TMP->open("> tmpfile.txt" or die "Your TMP file sucks"); until ($COMPFILE -> eof){ $compline = $COMPFILE->getline(); if ($compline !~ /END/){ print $TMP "$compline"; } } $TMP->open(">> tmpfile.txt" or die "Your TMP file sucks"); until ($COMPTMPLT -> eof){ $tmpltline = $COMPTMPLT->getline(); print $TMP "$tmpltline"; }

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://668859]
Approved by graff
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (5)
As of 2024-04-25 12:23 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found