Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
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 (Canon) 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 (Priest) 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 studying the Monastery: (6)
As of 2014-10-25 20:01 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    For retirement, I am banking on:










    Results (148 votes), past polls