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

Hello again monks!! It's been a while since I've delved into the world of Perl. I've so enjoyed your benevolence in the past and hope to again!

Well, I have to admit I am befuddled by my code. After a couple years away, I've decided to delve back into the llama and I'm farther along this time than last.

I'm up to chapter 9 where it asks the student in exercise 2 to :

"Write a program that makes a modified copy of a text file. In the copy, every string Fred (case insensitive) should be replaced with Larry. (So, "Manfred Mann" should become "ManLarry Mann".) The input filename should be given on the command line (don't ask the user), and the output file name should be the corresponding file name ending with .out.

Here's my answer so far...Some unnecessary code in there, but I'm still playing around with it.

#!/usr/bin/perl use strict; my $file = $ARGV[0]; if (!$file) { print "Hey! You didn't give me a file, sucka!\n"; } my $out = $file; open IN, "$file" or die "File did not open\n"; open OUT, "<$out" or die "File not available for write.\n"; $out =~ s/(\.\w+)?$/.out/; while (<IN>) { $out =~ s/fred/larry/gi; print OUT; }
But what I'm befuddled by is that the pattern match: $out =~ s/(\.\w+)?$/.out/; does not manipulate the output filename.

To my way of thinking, because the variable $out holds the file that's being fed to the program, the file name should be changed by the pattern match. Maybe the pattern match is only meant for the contents of the file, as opposed to the name of the file itself. I may not know how to manipluate the name of the file in the filesystem.

Not only that, but this code
while (<IN>) { $out =~ s/fred/larry/gi; print OUT; }
fails to perform the substitution.

Obviously there is some lameness in my thinking, I was hoping some sharp blade out there could set me straight on what I'm doing wrong.

You all da best!

Replies are listed 'Best First'.
Re: Pattern not manipulating file output
by NetWallah (Canon) on Feb 20, 2008 at 05:32 UTC
    Several issues:
    • open OUT "<$out" : opens the OUT handle for INPUT! You probably want ">"
    • The regex modifying $out is AFTER the 'open'. Should be before
    • In the regex, why do you have parens? How about $out=~s/\.\w+$/.out/
    • Replace $out =~ s/fred/larry/gi; with $_ =~ s/fred/larry/gi;
      •      "As you get older three things happen. The first is your memory goes, and I can't remember the other two... " - Sir Norman Wisdom

Re: Pattern not manipulating file output
by hipowls (Curate) on Feb 20, 2008 at 05:22 UTC

    • You are opening OUT for read, it shoud be open OUT, ">$file";
    • The file name for OUT is the same as the flie name of IN, you will find that you clobber the contents on $file before you do anything

    Open a tempory file, say "$file.tmp", write to that and then rename it to $file

    Put

    use strict; use warnings;
    at the start of the script

    Check you open the file handle

    open IN, $file or die "Can't open $file: $!\n";

Re: Pattern not manipulating file output
by apl (Monsignor) on Feb 20, 2008 at 12:35 UTC
    Rather than print OUT; you should consider print OUT "$out\n";

    That is, you have to specify what it is you want printed.

      Thanks to all you guys! I incorporated most of your suggestions, but haven't had the opportunity to incorporate all of them yet (I'm still at work).

      But here is the code as I've tweaked it that seems to work as the exercise intended:

      #!/usr/bin/perl use strict; use warnings; my $file = @ARGV[0]; if (!$file) { print "Hey! You didn't give me a file, sucka!\n"; } my $out = $file; $out =~ s/\.\w+?$/.out/; open IN, "<$file" or die "File did not open.\n"; open OUT, ">$out" or die "File not available for write.\n"; while (<IN>) { $_ =~ s/fred/\Ul\Earry/gi; }
      This code seems to work as intended. My only remaining confusion relates to these lines of code:
      my $out = $file; $out =~ s/\.\w+?$/.out/;
      now is the first line $out accepting the first index of @ARGV as a "file" or is it just accepting the name of the file.

      What I'm supposing is that $out just knows the name of the file as a scalar variable, or a string, and that the program is relying on the OUT filehandle to create a file with a name based on the scalar variable which has been manipulated by the pattern match. Any clarification on this point will be appreciated.