Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

upto match please, my one-lina!!

by Firefly258 (Beadle)
on Jun 08, 2006 at 23:50 UTC ( #554388=perlquestion: print w/ replies, xml ) Need Help??
Firefly258 has asked for the wisdom of the Perl Monks concerning the following question:

I'm looking for a way to get a perl one-liner print x lines of <> before a regex match. My initial, unfulfilling attempt goes like this .. (x is 4 here)

 perl -F/\\n/ -0ane 'for (0..$#F) {$c++; push @c, --$c if $F[$_]=~/regex/;} END{for (@c) {print join "\n", @F[($_-4)..$_]; print "\n---\n"}}' file

kinda works albeit kinda long. I'm interested in how you'd tackle this perl-oblem .. so, any ways of shortening/simplyfying it?

Comment on upto match please, my one-lina!!
Select or Download Code
Re: upto match please, my one-lina!!
by roboticus (Chancellor) on Jun 09, 2006 at 00:24 UTC
    Firefly258:

    Howzabout this?

    perl -ne 'print @t if /foo/; push @t,$_; shift @t if $#t>5' file
    You can even slice @t in the print if you want to have a larger gap between the last printed item and the regular expression...

    UPDATE: I golfed it down a little:

    perl -ne 'print @t if /foo/; @t=(@t[1..4],$_)' file
    --roboticus
      That doesn't print the "---\n" string or the correct lines. You want something like:
      perl -ne'@t=(@t[1..4],$_);/regex/&&die@t,"---\n"' file
        D'oh!

        I was having so much fun playing with one-liners that I forgot the parameters of the problem. I love that die trick.... I'll have to try it:

        perl -ne '@t=(@t[1..4],$_,"---\n");die@t if/foo/' file
        --roboticus
Re: upto match please, my one-lina!!
by davidrw (Prior) on Jun 09, 2006 at 00:26 UTC
    the obivous solution first :)
    egrep -B4 /foo/ file
    for perl, maybe like (not sure you want to slurp .. this just keeps an array of the last N lines):
    # put the line into the cache/queue; shorten the array if it's more t +han we want; print the array if current line mataches. perl -ne 'push @lines, $_; shift @lines if scalar(@lines)>4; print jo +in "", @lines if /foo/' file # if you don't want the current line printed as one of the 4, just rea +rrange a little: perl -ne 'print join "", @lines if /foo/; push @lines, $_; shift @lin +es if scalar(@lines)>4' file

    or, using Tie::File:
    use Tie::File; use Fcntl 'O_RDONLY'; my @array; tie @array, 'Tie::File', $ARGV[0], mode => O_RDONLY or die; foreach my $i ( 0 .. $#array ){ # no, doesn't handle index edge case of $i < 4 print join "", @array[$i-4,$i-1] if $array[$i] =~ /foo/; }
Re: upto match please, my one-lina!!
by jmcnamara (Monsignor) on Jun 09, 2006 at 00:35 UTC

    Here is a one-liner that emulates grep -B (although not as elegantly for adjacent matches):
    perl -ne '$a[$i=$.%4]=$_; print @a[$i+1..$#a,0..$i], "--\n" if /re +gex/' file

    --
    John.

      Thanks guys .. looks like it's a ubiquitous solution although approached via TMTOWTDI. Sure beats my long ineffeciency. :)
Re: upto match please, my one-lina!!
by NetWallah (Abbot) on Jun 09, 2006 at 00:55 UTC
    I'm adding my $0.02, in case the OP wants (as indicated by the OP's code) to print only the first occurrance of the match.
    perl -ne "push @a,$_;m/foo/ and exit 1;shift @a if $#a>3;END{$?==1 and + print @a }" myfile.txt
    Update: as japhy points out below, this is Win32 syntax. Use single-quotes for *nix.

         "For every complex problem, there is a simple answer ... and it is wrong." --H.L. Mencken

      $ which perl /usr/bin/perl $ perl -ne "push @a,$_; /foo/ and exit 1; shift @a if $#a>3; END{$?==1 + and print @a }" file Bareword found where operator expected at -e line 1, near "0a" (Missing operator before a?) syntax error at -e line 1, near "0a" Execution of -e aborted due to compilation errors.


      That sure is unexplained .. 0a??? where'd that come from. Seems the double quotes are playing a part in inducing this behaviour. Under singles it works fine.
        NetWallah is probably on Win32, where the double-quotes are necessity. Your unixy shell is interpolating $# and replacing it with '0' in your code; thus: shift @a if 0a>3;

        Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
        How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart
Re: upto match please, my one-lina!!
by japhy (Canon) on Jun 09, 2006 at 01:33 UTC
    perl -ne 'BEGIN { $pat = qr/.../; $size = (N-1) } @_ = ($_, @_[0 .. ($ +#_ > $size ? $size : $#_)]); print reverse @_ if /$pat/'

    Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
    How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart
      Jeff, Thanks for pointing $# out .. didnt realize that one. Errm, i dont see the point to the code .. seems like a long way around
      perl -ne 'print if /(?-xism:.{3})/'
        Huh? I presented code that prints N lines before a matching line.

        Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
        How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart
Re: upto match please, my one-lina!!
by ioannis (Vicar) on Jun 09, 2006 at 03:32 UTC
    So it can run also under use strict:

    perl -Mstrict \ -ne'/regex(?{print @@; exit})/;' \ -e'shift(@@) if push(@@,$_)>5' file
      Loved the clever use of the return value from push, ioannis (++). The 'experimental' regex feature, however, got me thinking if it could be done with regular features only, so - here is the slightly ugly, but short:
      perl -ne "m/foo/ and die @@ ; shift(@@) if push(@@,$_)>5" myfile.txt
      I used "die" because (without eval), the "print @@, exit" combo printed nothing in my code (but it works as advertised in ioannis' code). Perhaps a more enlightened monk could explain why.

      Update: This works too:

      perl -Mstrict -ne "m/addr/ and eval {print @@; exit}; shift(@@) if pus +h(@@,$_)>5" myfile.txt
      This code works on Win32. Use single-quotes for *nix.

           "For every complex problem, there is a simple answer ... and it is wrong." --H.L. Mencken

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://554388]
Approved by Moriarty
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (6)
As of 2015-07-06 01:41 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 (68 votes), past polls