Read the file check the sequence

Viewed 120

I am reading a file like this

1
one
2
two
3
three
three
three
four
five
5

In this I want check the sequence one two three four five and print how many times three is present.

My code:

use warnings;
use strict;

open(tempp1,"<$temp1") or die "Could not open file $temp1: $!";
 my $count = 0;
while(my $line=<tempp1>) {
  if ($line eq "one") {

  while(my $line=<tempp1>) {
   if ($line eq "two") {
    
   while(my $line=<tempp1>) {
    if ($line eq "three") {
     $count++;

     while(my $line=<tempp1>) {
      if ($line eq "four") {

       while(my $line=<tempp1>) {
        if ($line eq "five") {
         last;
}}}}}}}}}}
print "$count\n";
close tempp1;

Output is printing :1 How to correct this?

3 Answers

The problems is that you immediately start looking for four as soon as three is encountered when you should be looking for both three and four.

The simple answer is to replace

   while(my $line=<tempp1>) {
    if ($line eq "three") {
     $count++;

     while(my $line=<tempp1>) {
      if ($line eq "four") {

with

   while(my $line=<tempp1>) {
    if ($line eq "three") {
     $count++;

     while(my $line=<tempp1>) {
      if ($line eq "three") {
        $count++;
      }
      elsif ($line eq "four") {

But it's unclear if that produces the desired result. Consider the following input:

           # Possible Sequence 1   Possible Sequence 2
           # -------------------   -------------------
one        # one                   one
two        # two                   two
three      # three                 three
three      # three                 three
four       # four                  
three      #                       three
three      #                       three
three      #                       three
four       #                       four
five       # five                  five
           # -------------------   -------------------
           # 2 instances           5 instances

Should count be 2 (stop counting when four is found) or 5 (the largest possible)? The above solution would return 2.

Also, note that you don't currently check if four and five were found, but you suggested that this is required.

The reason it does not work is pointed out on ikegami's answer.

But, also, as an alternative, you may consider using a regex-based solution.

For example:

use strict;
use warnings;

my $file_content;
do { # we use a do block to change the line terminator locally
    local $/ = undef; # set line terminator as undef so we will read whole file
                      # when we would try to read a line
    open my $fh, '<', 'file.txt' or die $!;
    $file_content = <$fh>; # now it reads the whole file
    close $fh or die $!;
};

if ($file_content =~ m/ ^ one\R two\R ((?:three\R)+) four\R five $ /ixm) {
    print "Number of 'three's is: " . split m/\R/, $1;
    print "\n";
} else {
    die 'I could not find a valid sequence';
}

(Note that since this reads the file as a whole, you need enough memory to hold it)

Then you try to match the file content using this regex:

m/
    ^                     # start of line
        one\R             # literal 'one' + end of line character/s
        two\R 
        ((?:three\R)+)    # One or more (+) "three" + end of line repetitions
                          # everything holded on a capturing group (outer parentheses)
        four\R 
        five
    $                     # end of line (a character is not required)
/ixm # i = ignore case
     # x = ignore whitespace and allows comments
     # m = ^ and $ match begin and enf of line (instead of begin and end of string)

Which serves as two purposes:

  • Check that you find a valid 1, 2, 3, ..., 4, 5 sequence
  • Capture the 3, ..., 3 part

The 3, ..., 3 part is captured on the first capturing group ($1) Then you split that content by lines and the number of lines you have is the number of threes

I would look for the lines like this.

use strict;
use warnings;
use English;

my $counter=0;
my $threes = 0;
my @lines_to_match = qw(one two three four five); 

open( my $fh , "<" , "file.txt") or die $OS_ERROR;
while ( my $line = readline($fh) )
{
  if ( $counter < scalar(@lines_to_match) and $line =~m/$lines_to_match[$counter]/ )  
  {
    $counter++;
  }
  $threes++ if $line =~m/three/;
}
close($fh);

print "counter = $counter - threes = $threes\n";

You can check if all items are matched with

print "true" if $counter == scalar(@lines_to_match);

You can also check the last match was "three" by using one of the following

$threes++ if $line =~m/three/ and $counter==3;
$threes++ if $line =~m/three/ and $line=~ m/$lines_to_match[$counter-1]/;
Related