Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

I want to write a function, you call it ,it will return one matched record each time!

by dwslovedh (Novice)
on Apr 18, 2013 at 12:02 UTC ( [id://1029328]=perlquestion: print w/replies, xml ) Need Help??

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

Hi there, I want to write a function that can return one record from a file ervery time, for example, the records in input.txt are like this:

_________________________ 12 dd DH: mm struct{ int a; char b; m1 struct { int c; int d; }; m2 struct { int e; int f; }; } 2 dfdkk df dd } 1 LOCAL_PARAM: ssi_struct { ref = 0; header = { req = 0xa; }; } DH: mm struct{ int a; char b; m1 struct { int c; int d; }; } ____________________________________

I want to use a function to extract the records starting with "DH:" each time I call it,like this $record = get_record("input.txt"); So I must remember the position of the file last read, and continue to extract the record. I use the seek and tell, but it didn't work. Here is the script:

sub get_record_from_file { my $filein = shift; my $regex = shift; my $pos = shift open FILEIN, "<$filein" or die "!$\n"; seek(FILEIN, $pos, 0); my $in_block = 0; my $last = "}"; my @array = {}; foreach my $line (<FILEIN>) { if ($line =~ /$regex/) { $in_block = 1; } if ($in_block) { push @array, $line; } if ($line =~ m/$last$/) { $in_block = 0; } } $pos = tell FILEIN; return (\@array, $pos); } $record = get_record_from_file("input.txt","DH:",0);

Can anyone help? Thanks:)

Update

correct some mistakes: Here is the script:

sub get_record_from_file { my $filein = shift; my $regex = shift; my $pos = shift open FILEIN, "<$filein" or die "!$\n"; seek(FILEIN, $pos, 0); my $in_block = 0; my $last = "}"; my @array = {}; foreach my $line (<FILEIN>) { if ($line =~ /$regex/) { $in_block = 1; } if ($in_block) { push @array, $line; } if ($line =~ m/$last$/) { $in_block = 0; last; } } $pos = tell FILEIN; return (\@array, $pos); } my $curpos = 0; ($record,$curpos) = get_record_from_file("input.txt","DH:",$curpos);

The $curpos is not updated. For example, you call the function once, and return the $curpos = 174; next time I call it, $curpos is still 174. Thanks:)

Replies are listed 'Best First'.
Re: I want to write a function, you call it ,it will return one matched record each time!
by Jenda (Abbot) on Apr 18, 2013 at 15:51 UTC

    You either want to construct an iterator:

    sub open_record_file { my $filein = shift; my $regex = shift; open my $FH, "<$filein" or die "$!\n"; return sub { my $in_block = 0; my $last = "}"; my @array; while (my $line = <$FH>) { if ($line =~ /$regex/) { $in_block = 1; } if ($in_block) { push @array, $line; } if ($line =~ m/$last$/) { $in_block = 0; last; } } return (@array ? \@array : undef); } } my $next_record = open_record_file("input.txt",'DH:'); while (my $record = $next_record->()) { # do something with the array in $record } undef $next_record;
    or create a class.

    Update: Fixed incorrect filehandle in the while loop. Thanks to poj.

    Jenda
    Enoch was right!
    Enjoy the last years of Rome.

Re: I want to write a function, you call it ,it will return one matched record each time!
by kcott (Archbishop) on Apr 18, 2013 at 15:52 UTC

    G'day dwslovedh,

    Welcome to the monastery.

    I read your post which looked like this:

    ----- OP's original post starts ----------------------------

    Hi there, I want to write a function that can return one record from a file ervery time, for example, the records in input.txt are like this:

    _________________________ 12 dd DH: mm struct{ int a; char b; m1 struct { int c; int d; }; m2 struct { int e; int f; }; } 2 dfdkk df dd } 1 LOCAL_PARAM: ssi_struct { ref = 0; header = { req = 0xa; }; } DH: mm struct{ int a; char b; m1 struct { int c; int d; }; } ____________________________________

    I want to use a function to extract the records starting with "DH:" each time I call it,like this $record = get_record("input.txt"); So I must remember the position of the file last read, and continue to extract the record. I use the seek and tell, but it didn't work. Here is the script:

    sub get_record_from_file { my $filein = shift; my $regex = shift; my $pos = shift open FILEIN, "<$filein" or die "!$\n"; seek(FILEIN, $pos, 0); my $in_block = 0; my $last = "}"; my @array = {}; foreach my $line (<FILEIN>) { if ($line =~ /$regex/) { $in_block = 1; } if ($in_block) { push @array, $line; } if ($line =~ m/$last$/) { $in_block = 0; } } $pos = tell FILEIN; return (\@array, $pos); } $record = get_record_from_file("input.txt","DH:",0);

    Can anyone help? Thanks:)

    ----- OP's original post ends ------------------------------

    I came up with a solution and clicked on the "Comment on" link to post it. I then found your posting had completely changed to this:

    Please do not do this. If you want to cancel something you've posted, put <strike>...</strike> tags around the whole block of markup; add replacement text if that's appropriate; then add an Update: section which explains the changes you've made.

    Here's my solution to your original problem:

    #!/usr/bin/env perl use strict; use warnings; my $sep = '=' x 60 . "\n"; (my $dh_file = $0) =~ s/pl$/dat/; open_dh($dh_file); while (1) { print 'Get next DH record (y/n): '; my $reply = <>; if ($reply =~ /^y/i) { print "Next DH record:\n"; my $dh_record = read_dh(); print "$sep$dh_record\n$sep"; if (eof_dh()) { print "No more DH records!\n"; last; } } else { print "Stopped reading DH records.\n"; last; } } close_dh(); { my $dh_fh; sub open_dh { my $dh_file = shift; open $dh_fh, '<', $dh_file or die "Can't read $dh_file: $!"; my $discard = read_dh(); return; } sub read_dh { local $/ = 'DH: '; my $dh_trim_re = qr{\A \s* (.*?) \s* (?: DH: \s )? \z}msx; my $dh_record = <$dh_fh>; $dh_record =~ s/$dh_trim_re/$1/; return $dh_record; } sub close_dh { close $dh_fh; return; } sub eof_dh { return eof $dh_fh; } }

    Here's a sample run:

    $ pm_get_multi_rec.pl Get next DH record (y/n): y Next DH record: ============================================================ mm struct{ int a; char b; m1 struct { int c; int d; }; m2 struct { int e; int f; }; } 2 dfdkk df dd } 1 LOCAL_PARAM: ssi_struct { ref = 0; header = { req = 0xa; }; } ============================================================ Get next DH record (y/n): y Next DH record: ============================================================ mm struct{ int a; char b; m1 struct { int c; int d; }; } ============================================================ No more DH records!

    -- Ken

Re: I want to write a function, you call it ,it will return one matched record each time!
by Corion (Patriarch) on Apr 18, 2013 at 12:33 UTC

    You seem to want to remember where you last left of in FILEIN. To debug your issue, I recommend you print out where each block was found and where it ended.

    As a second hint, compare the behaviour of</c>

    foreach my $line (<FILEIN>) { ...

    and

    while (my $line= <FILEIN>) { ...

    with respect to $pos.

Re: I want to write a function, you call it ,it will return one matched record each time!
by LanX (Saint) on Apr 18, 2013 at 13:22 UTC
    see Re: Split string after 14 Line Feeds? as a recipe for how to write nested iterators.

    iterator := "function, you call it ,it will return one matched record each time" till stream exhausted

    Cheers Rolf

    ( addicted to the Perl Programming Language)

Re: I want to write a function, you call it ,it will return one matched record each time!
by hdb (Monsignor) on Apr 18, 2013 at 12:31 UTC

    Two observations:

    You always read in the whole file. You need to stop once you found what you were looking for. E.g. replace $in_block = 0; with last;

    You need to store the new position returned from your function call and pass it back on the next call to the function. Currently, you only keep the record.

Re: I want to write a function, you call it ,it will return one matched record each time!
by poj (Abbot) on Apr 18, 2013 at 17:09 UTC
    6 more to correct..
    # 1) add use strict; sub get_record_from_file { my $filein = shift; my $regex = shift; # 2) add ; at end my $pos = shift; open FILEIN, "<$filein" or die "!$\n"; seek(FILEIN, $pos, 0); my $in_block = 0; my $last = "}"; # 3) change {} to () my @array = (); # 4) change from foreach to while while (my $line=<FILEIN>) { if ($line =~ /$regex/) { $in_block = 1; } if ($in_block) { push @array, $line; } # 5) add $in_block if (($in_block) && ($line =~ m/$last$/)) { $in_block = 0; last; } } $pos = tell FILEIN; return (\@array, $pos); } my $curpos = 0; # 6) add my my ($record,$curpos) = get_record_from_file("input.txt","DH:",$curpos) +; # show results print for @$record; print "----\n"; ($record,$curpos) = get_record_from_file("input.txt","DH:",$curpos); print for @$record;
    poj

      Sorry for the wrong action. I known it now:) And really thank you for all the help.

Re: I want to write a function, you call it ,it will return one matched record each time!
by RichardK (Parson) on Apr 18, 2013 at 12:30 UTC

    'it didn't work' isn't very descriptive and doesn't tell us anything useful.

    But, as I have to guess, I'd say it's that the pattern in $last is too general, it will match not only the end of your block but also the end of struct m1.

Re: I want to write a function, you call it ,it will return one matched record each time!
by Anonymous Monk on Apr 18, 2013 at 12:18 UTC

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others rifling through the Monastery: (5)
As of 2024-04-16 16:58 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found