Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
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 ( #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:)

Comment on I want to write a function, you call it ,it will return one matched record each time!
Select or Download Code
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 (Abbot) on Apr 18, 2013 at 15:52 UTC

    G'day dwslovedh,

    Welcome to the monastery.

    I read your post which looked like this:

    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 (Pope) 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 (Canon) 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 (Prior) 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 (Priest) 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 (Vicar) 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
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? | Other CB clients
Other Users?
Others having an uproarious good time at the Monastery: (5)
As of 2015-07-30 03:01 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









    Results (269 votes), past polls