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

Ok, so here's what I'm trying to do. I have a .txt file of a messaging history going back and forth between myself and another person. Throughout the file, it has one of our names, then a line break, then what we said (sometimes multiple paragraphs), etc. (Sometimes the same person said something twice in a row, so the name appears again.) What I want to do is have my perl script go through this file and split it up into two files: one of things I said, one of things my friend said.

What I thought I could do is read in the whole file into an array, line by line, and then whenever the next line is "Steffi Lastname" or "Daniel Lastname" tell it that it should be writing to that person's output file.

I'm pasting my code (which isn't working) below. I've figured out that it isn't updating my $printto variable, so in the last two if loops it isn't matching with "Daniel" or "Steffi." (I tried initizing the $printto to "Daniel" and then it just copied the whole messages.txt file into Daniel.txt and didn't put anything into Steffi.txt.) What am I doing wrong?

(And yes, I am aware that I'm not using strict or warnings, and that I should be, but if that can be overlooked for this particular script I would rather not. I am very new to Perl and don't know how to make any of it work at all while using strict and warnings.)

open (FILE, "<messages.txt") or die ("Name the input file 'messages.tx +t' and make sure it is in the correct directory."); open (DANIEL, ">Daniel.txt"); open (STEFFI, ">Steffi.txt"); @lines = <FILE>; #reads the file into an array, with each element in t +he array containing one line $numberOfLines = @lines; #number of elements in the input array $lineNumber = 0; $printto; while ($lineNumber < $numberOfLines) { if ($lines[$lineNumber] eq "Daniel Lastname") { $printto = "Daniel"; } if ($lines[$lineNumber] eq "Steffi Lastname") { $printto = "Steffi"; } if ($printto eq "Daniel") { print DANIEL "$lines[$lineNumber]"; $lineNumber++; } if ($printto eq "Steffi") { print STEFFI "$lines[$lineNumber]"; $lineNumber++; } } close(DANIEL); close(STEFFI);
  • Comment on Working with text files, thinking my issue is with variables inside if loops
  • Download Code

Replies are listed 'Best First'.
Re: Working with text files, thinking my issue is with variables inside if loops
by jdporter (Paladin) on May 24, 2011 at 01:11 UTC

    Most likely it is due to the fact that your input lines contain newline characters at the end but you're comparing them to literal values which do not contain such newlines. Probably the easiest (though not necessarily the best) way to deal with this is simply to chomp the array of lines immediately after reading it:

    chomp @lines;
    There are numerous other optimizations you could make; I'll leave the pedants to show those to you.

    I reckon we are the only monastery ever to have a dungeon stuffed with 16,000 zombies.
Re: Working with text files, thinking my issue is with variables inside if loops
by dasgar (Priest) on May 24, 2011 at 05:30 UTC

    Although a few others have posted good information already, I'll toss in my two cents.

    And yes, I am aware that I'm not using strict or warnings, and that I should be, but...

    Speaking from personal experience, I'd recommend getting into the habit of using these lines of code, which will help you identify problems sooner.

    Also, I noticed that you only error checked on just one of the 3 files that you opened, but you didn't print out the $! variable that contains detailed information about why the open command fails. If you add that in every time you open a file, it will help to quickly identify the source of problems if open fails.

    Applying the above thoughts along with the stuff from jdporter's and blakew's posts, I'd rewrite your code as the following untested code:

    use strict; use warnings; open(FILE,"<messages.txt") or die "Unable to open file 'messages.txt': + $!\n"; open(my $daniel,">Daniel.txt") or die "Unable to open file 'Daniel.txt +': $!\n"; open(my $steffi,">Steffi.txt") or die "Unable to open file 'Steffi.txt +': $!\n"; my $fh = "none"; while (<FILE>) { chomp; if (/^\s*Daniel\s+Lastname\s*$/s) {$fh = $daniel;} if (/^\s*Steffi\s+Lastname\s*$/s) {$fh = $steffi;} if ($fh ne "none") {print $fh $_;} } close($steffi); close($daniel); close(FILE);

    Hopefully the code above or from blakew's post will help get you going the right direction.

      Don't forget to add a "\n" when you print the message to the file! You have chomped the original "\n"!

      CountZero

      A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

        Good catch! Since I usually don't use variables for filehandles in the code that I write, I got a little too focused on the filehandles and overlooked that detail.

Re: Working with text files, thinking my issue is with variables inside if loops
by blakew (Monk) on May 24, 2011 at 03:05 UTC
    Change to
    while (<FILE>) { next unless /\S/; # Skip whitespace lines if (/^ \s* Daniel \s+ Lastname \s* $/x) { $printto = "Daniel"; } elsif (/^ \s* Steffi \s+ Lastname \s* $/x) { $printto = "Steffi"; } elsif ($printto eq "Daniel") { print DANIEL $_; } elsif ($printto eq "Steffi") { print STEFFI $_; } }
      Suboptimal.
      while (<FILE>) { next unless /\S/; # Skip whitespace lines if (/^ \s* Daniel \s+ Lastname \s* $/x) { $current_handle = daniels_handle; next; } elsif (/^ \s* Steffi \s+ Lastname \s* $/x) { $current_handle = steffis_handle; next; } print $current_handle $_; }


      holli

      You can lead your users to water, but alas, you cannot drown them.