Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

Flip-flop reset?

by swkronenfeld (Hermit)
on Aug 29, 2006 at 19:41 UTC ( [id://570232]=perlquestion: print w/replies, xml ) Need Help??

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

Is there a way to reset a flip-flop operator? For example, I have the following text that I am searching for, in which I am scanning for processes which have a ':D' appended to the back of the :\d:\d (i.e. :0:0:D). There are a number of lines above the lines that I show, however there are no lines below.
. <snip> . ClientSystemName (clisysname): 'SPIFF', Client LongId: '0008027E1180,/ +epic/tst/cachesys/mgr/' PIDTAB for 128 jobs: (Job:PID:reswake:sflg[:D if dead] Job: PID:resw:SF:D 1: 5382 :0:0 2: 5384 :0:0 3: 5385 :0:0 4: 5386 :0:0 5: 5394 :0:0 6: 5387 :0:0 7: 5388 :0:0 8: 5389 :0:0 9: 5390 :0:0 10: 5391 :0:0 11: 5392 :0:0 12: 5393 :0:0 13: 5456 :0:0 14: 5444 :0:0 15: 5445 :0:0 16: 14682 :1:0:D 17: 5450 :0:0 19: 5453 :0:0 20: 14626 :0:0:D

Here's my code,
sub mySub { foreach ( @arr ) { if ( /^PIDTAB/ ... /^\n/ ) { next if ( /^(PIDTAB|\n)/ ); while ( /\s+(\d+):\s+(\d+)\s*:\S+:\S+:D\s+/g ) { # do something } } } }
This works fine the first time through. However, sometimes my flop never evaluates to true, because there is not a blank line at the end of my output. Since the flop will never evaluate to true, the next time I run mySub the operator will be in the true state.

Of course, I can just keep track of the state in a scalar rather than using the flip-flop operator, or I could do some kind of @arr manipulation. But I'm figuring that there is a Perl way of solving this problem that I'm not aware of. Any input is appreciated.

Some further clarification on the text I'm processing:
-sometimes there will be a final line with a newline, sometimes the last line shown there is the last line of input
-The number of lines of processes is unknown, and does not have any "keyword" that I'm aware of.

Update: The match is looking for :\d:\d, not :0:0, thanks to aartisesha for pointing out the error in my question.

Replies are listed 'Best First'.
Re: Flip-flop reset?
by sgifford (Prior) on Aug 30, 2006 at 01:37 UTC
    Interesting question. I'm not sure of the answer, but a kludgey workaround is to always make sure you start with something that will cause the flip-flop to reset:
    foreach ( "\n",@arr ) { ...
      Nice idea sgifford. I think that what I may do is actually put the newline at the end
      foreach (@arr, "\n") {
      They should work identically, as far as I can tell, but I can verify that the operator flops before leaving the subroutine now. This should work for both cases of input as I stated above.

      Thanks for everyone's input.
        That will only work if you are certain nothing in your for loop will bail out early, including something throwing an exception that's caught by a caller of your sub. Putting the dummy "\n" at the beginning of the loop is safer.
Re: Flip-flop reset?
by cdarke (Prior) on Aug 29, 2006 at 20:01 UTC
    One possibility is to chomp before the 'if', and make your flop /^$/, that is an empty line.
      The problem is not that a newline is not present, it is that (in the above case) the last line is
      17: 5450  :0:0   19: 5453  :0:0   20: 14626 :0:0:D
      There is not another line afterwards, but I have no text clues that that is the last line containing process information.

      Here is two input samples, to hopefully make this more clear than my explanation. (The lines of hyphens are delimiters, and they are not in my input).
      --------------------------------------------------------- ClientSystemName (clisysname): 'SPIFF', Client LongId: '0008027E1180,/ +epic/tst/cachesys/mgr/' PIDTAB for 128 jobs: (Job:PID:reswake:sflg[:D if dead] Job: PID:resw:SF:D 1: 5382 :0:0 2: 5384 :0:0 3: 5385 :0:0 4: 5386 :0:0 5: 5394 :0:0 6: 5387 :0:0 7: 5388 :0:0 8: 5389 :0:0 9: 5390 :0:0 10: 5391 :0:0 11: 5392 :0:0 12: 5393 :0:0 13: 5456 :0:0 14: 5444 :0:0 15: 5445 :0:0 16: 14682 :1:0:D 17: 5450 :0:0 19: 5453 :0:0 20: 14626 :0:0:D ------------------------------------------------------- ClientSystemName (clisysname): 'SPIFF', Client LongId: '0008027E1180,/ +epic/tst/cachesys/mgr/' PIDTAB for 128 jobs: (Job:PID:reswake:sflg[:D if dead] Job: PID:resw:SF:D 1: 5382 :0:0 2: 5384 :0:0 3: 5385 :0:0 4: 5386 :0:0 5: 5394 :0:0 6: 5387 :0:0 7: 5388 :0:0 8: 5389 :0:0 9: 5390 :0:0 10: 5391 :0:0 11: 5392 :0:0 12: 5393 :0:0 13: 5456 :0:0 14: 5444 :0:0 15: 5445 :0:0 16: 14682 :1:0:D 17: 5450 :0:0 19: 5453 :0:0 20: 14626 :0:0:D From Directory: /releng/b/obj/5.0.20/build6305_0_3627/linux The time is: Tue Aug 29 14:11:17 2006 . . . ------------------------------------------------------
      So there can be more random junk that I don't want to include after the process list that I'm looking at. In that case, my flip flop works, however when my input ends abruptly, without the extra blank line, I don't have a way of resetting it.

      Like I said above, I can just keep track of the state in a scalar, maybe that is the better way to do it. I just thought that there may be a different solution.
Re: Flip-flop reset?
by Dietz (Curate) on Aug 30, 2006 at 06:02 UTC

    You could make sure that your last array element always ends with a newline before processing it, to use your existing code:

    $arr[-1] .= "\n";

Re: Flip-flop reset?
by aartisesha (Novice) on Aug 30, 2006 at 06:54 UTC
    Here is my suggestion:
    foreach $line (@arr) { if ( $line =~ m{\s+\d+:\s+\d+\s*:(\S+:\S+:D\n?)$}g ) { #do something } }

    To clarify: Are you concerned of matching (0:0:D) i.e. as per your statement "which I am scanning for processes which have a ':D' appended to the back of the :0:0"? The current expression given by you matches

    13: 5456 :0:0 14: 5444 :0:0 15: 5445 :0:0 16: 14682 :1:0:D 17: 5450 :0:0 19: 5453 :0:0 20: 14626 :0:0:D
Re: Flip-flop reset?
by ysth (Canon) on Aug 30, 2006 at 21:56 UTC
    my @arr = ...; sub mySub { goto &{ sub { # added line foreach ( @arr ) { if ( /^PIDTAB/ ... /^\n/ ) { next if ( /^(PIDTAB|\n)/ ); while ( /\s+(\d+):\s+(\d+)\s*:\S+:\S+:D\s+/g ) { # do something } } } }} # added line }
    will do the trick, since the sub {} will get a new pad (where the .. state is stored) each time mySub is called. This only works if the sub is a closure (uses an outer lexical); otherwise, the sub{} is treated more as if it were a kind of constant, and doesn't get a new pad each time the reference is returned by sub. If @arr isn't lexical, you can still force a closure by replacing
    goto &{ sub {
    with
    my $dummy; goto &{ sub { $dummy if 0;
      I was recently wondering how to do this, and why a regular anonymous sub (w/o closures) wouldn't work. Then I found this node. Though my solution (before finding this) was to generate an anonymous sub using eval $string. E.g.
      my $range_checker = eval 'sub { local $_ = shift; /foo/../bar/ }';
      At first, your way seems a little too indirect and magical, but it makes perfect sense if you create a 'flip-flop generator':
      sub mk_flip_flop { my ( $re1, $re2 ) = @_; sub { local $_ = shift; /$re1/../$re2/ } }
      I was thinking, local $.; has the odd, but documented, effect of localizing the last-read-filehandle. Maybe it could be extended to localize the state of ../... too. :)

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others imbibing at the Monastery: (6)
As of 2024-04-18 15:04 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found