Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

Re^3: How to parse a text file

by jethro (Monsignor)
on Aug 10, 2009 at 16:47 UTC ( [id://787375]=note: print w/replies, xml ) Need Help??


in reply to Re^2: How to parse a text file
in thread How to parse a text file

Generally your program would have been better written as a Finite-state_machine, further examples here and here. Basically you read each line and decide in a big switch or if-then-else construct, what the next state should be. That is something you are already doing a little with $bset and $bend, but then you try to read and parse 4 lines in one go and it gets complicated and you have to write a lot of code more than once.

A state machine helps to prevent this. You have only one place where you read a line from the file. Then depending on state and line you do something and change the state

In your case there would be one state "outside define service" and one state "inside define service" (you can use a number to denote state but you should document what that number means). If you are in state "inside define service" there are three cases:

1) the line begins with "service_description": You don't print the line but push the line into an array. Set a flag that tells you you have seen it

2) the line begins with some other text: You don't print the line but push the line into an array.

3) the line is a '}': look for the 'use' line in the array and remove the sam if the flag is not set. Print the array and set the state to "outside define service".

In the "outside define service" state you just look for a "define service" line and if you find one, change state and clear the array and flag

The program would look something like this:

... my $state="outside"; my @servicelines; my $desc_flag; #is 1 if description found while ($line = <TEXT_FILE>) { if ($state eq "outside") { print MYFILE $line; if ($line=~/^\s*define service/) { $state="inside"; @servicelines=(); $desc_flag=0; } } else if ($state eq "inside") { if ($line=~/^\s*}/) { @servicelines= removesam(@servicelines) if ($desc_flag); print @servicelines; print $line; $state="outside"; } elsif ($line=~/^\s*service_description/) { push @servicelines, $line; $desc_flag=1; } else { push @servicelines, $line; } } } ...

Missing from above is the sub removesam, also any error checks, to warn you if the file you are parsing is not conforming to expectations. For example a '}' line in state "outside" should print a warning. Also as a general advice you should add "use warnings;" and "use strict;" at the start of your program even though strict mode is slightly more work for you, it prevents errors.

Replies are listed 'Best First'.
Re^4: How to parse a text file
by xoroz (Initiate) on Aug 11, 2009 at 10:59 UTC

    Jethro, you are the man.
    You saved my day, the concept of Finite-state machine is perfect!
    I modified a little few things and the script now works.
    living and learning.
    thanks again brother
    here is the final script:

    #! /usr/local/bin/perl # must add service_description inside "define service{" only in defini +tions that do not have it #Version 6 my $state="outside"; my @servicelines; my $desc_flag; #is 1 if description found(already exists, if i +ts 0 then call parse and output sd) my $file = "<test.txt"; my $sd = ""; open (MYFILE, '>services2.cfg'); open (TEXT_FILE, $file) || die "Can't open $file for read: $!"; while ($line = <TEXT_FILE>) { if ($state eq "outside") { if ($line=~/^\s*define service/) { $state="inside"; @servicelines=(); #reset array push(@servicelines,$line ); $desc_flag=0; } } elsif ($state eq "inside") { if ($line=~/^\s*}/) { if ($desc_flag eq 0){ foreach $l(@servicelines) { if ($l=~/^\s*use/) { $sd = removesem($l); #print $sd; push(@servicelines,$sd); } } } push(@servicelines, "}\n"); # go thru entire array and print to file foreach $i(@servicelines) { print $i; print MYFILE $i; } $state="outside"; } elsif ($line=~/^\s*service_description/) { push(@servicelines, $line); $desc_flag=1; } else { push(@servicelines, $line); } } } close (TEXT_FILE); close (MYFILE); sub removesem($) { my $use = shift; $use =~ s/use/service_description/; #print "test: " . $use . " \n"; if($use =~ m/sem/ ) { #remove sem $use =~s/sem_//; return $use; }else{ return $use; } } # Perl trim function to remove whitespace from the start and end of th +e string sub trim($) { my $string = shift; $string =~ s/^\s+//; $string =~ s/\s+$//; return $string; }

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (3)
As of 2024-04-19 22:42 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found