help on regular expression

Discussion in 'Perl Misc' started by Tao Li, Aug 27, 2009.

  1. Tao Li

    Tao Li Guest

    I have been thinking the problem for a while, please help me.

    There is a log file. Its format is like this:

    send ........
    send ........
    .................
    .............
    send..........
    ....................
    .................
    send..........
    heartbeat..........
    ................
    send........
    ............
    ..........
    send..........
    send.........
    send..........
    heartbeat..........
    .....
    send...
    ......
    heatbeat....
    .....

    I want to find all the "send line" before "heartbeat line",

    send...
    send...
    heartbeat...

    doesn't include anything like this:

    send...
    ......
    send...
    heartbeat..........
    Tao Li, Aug 27, 2009
    #1
    1. Advertising

  2. Tao Li

    Tao Li Guest

    if you can do it with one-liner, that would be wonderful.

    On Aug 27, 12:36 am, Tao Li <> wrote:
    > I have been thinking the problem for a while, please help me.
    >
    > There is a log file. Its format is like this:
    >
    > send ........
    > send ........
    > ................
    > ............
    > send..........
    > ...................
    > ................
    > send..........
    > heartbeat..........
    > ...............
    > send........
    > ...........
    > .........
    > send..........
    > send.........
    > send..........
    > heartbeat..........
    > ....
    > send...
    > .....
    > heatbeat....
    > ....
    >
    > I want to find all the "send line" before "heartbeat line",
    >
    > send...
    > send...
    > heartbeat...
    >
    > doesn't include anything like this:
    >
    > send...
    > .....
    > send...
    > heartbeat..........
    Tao Li, Aug 27, 2009
    #2
    1. Advertising

  3. Tao Li wrote:
    > I have been thinking the problem for a while, please help me.
    >
    > There is a log file. Its format is like this:
    >
    > send ........
    > send ........
    > ................
    > ............
    > send..........
    > ...................
    > ................
    > send..........
    > heartbeat..........
    > ...............
    > send........
    > ...........
    > .........
    > send..........
    > send.........
    > send..........
    > heartbeat..........
    > ....
    > send...
    > .....
    > heatbeat....
    > ....
    >
    > I want to find all the "send line" before "heartbeat line",
    >
    > send...
    > send...
    > heartbeat...
    >
    > doesn't include anything like this:
    >
    > send...
    > .....
    > send...
    > heartbeat..........


    perl -ne'
    if ( /^send/ ) { push @buff, $_ }
    elsif ( /^heartbeat/ ) { print @buff, $_ }
    else { @buff = () }
    '


    John
    --
    Those people who think they know everything are a great
    annoyance to those of us who do. -- Isaac Asimov
    John W. Krahn, Aug 27, 2009
    #3
  4. >>>>> "Tao" == Tao Li <> writes:

    Tao> if you can do it with one-liner, that would be wonderful.

    If I had a pony, it'd also be wonderful.

    If I was six foot tall at my current weight, my BMI would be proper,
    and that'd also be wonderful.

    Why do you care if it's a one-liner?

    print "Just another Perl hacker,"; # the original

    --
    Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
    <> <URL:http://www.stonehenge.com/merlyn/>
    Smalltalk/Perl/Unix consulting, Technical writing, Comedy, etc. etc.
    See http://methodsandmessages.vox.com/ for Smalltalk and Seaside discussion
    Randal L. Schwartz, Aug 27, 2009
    #4
  5. Tao Li

    ccc31807 Guest

    On Aug 27, 1:36 am, Tao Li <> wrote:
    > I want to find all the "send line" before "heartbeat line",


    I don't see this as a RE problem at all, although you would use REs.
    You can very easily create an algorithm to do what you want by simply
    stepping through the file by hand. You might want to do something like
    this:

    assign the current line to var1
    for each line -
    assign the next line to var2
    print var2 if var1 /^send/ and var2 /^heartbeat/
    assign var2 to var1

    Yes, this is a simplistic and crude way to do this, but all other
    things being equal, the best way is usually the simplest and crudest
    way, rather than a more complex and complicated way.

    CC
    ccc31807, Aug 27, 2009
    #5
  6. ccc31807 <> wrote:
    >On Aug 27, 1:36 am, Tao Li <> wrote:
    >> I want to find all the "send line" before "heartbeat line"?

    >
    >I don't see this as a RE problem at all, although you would use REs.


    Actually no, or only if identifying the line(s) requires a RE.

    Otherwise a simpler index() call is more appropriate and doesn't require
    a \Q....\E esacape.

    jue
    Jürgen Exner, Aug 27, 2009
    #6
  7. Tao Li

    C.DeRykus Guest

    On Aug 26, 10:36 pm, Tao Li <> wrote:
    > I have been thinking the problem for a while, please help me.
    >
    > There is a log file. Its format is like this:
    >
    > send ........
    > send ........
    > ................
    > ............
    > send..........
    > ...................
    > ................
    > send..........
    > heartbeat..........
    > ...............
    > send........
    > ...........
    > .........
    > send..........
    > send.........
    > send..........
    > heartbeat..........
    > ....
    > send...
    > .....
    > heatbeat....
    > ....
    >
    > I want to find all the "send line" before "heartbeat line",
    >
    > send...
    > send...
    > heartbeat...
    >
    > doesn't include anything like this:
    >
    > send...
    > .....
    > send...
    > heartbeat..........


    If you don't mind capturing hits from the bottom of the
    log first, you could use File::ReadBackwards (which is o
    ften useful for reading logfiles):

    use File::ReadBackwards;

    my $bw = File::ReadBackwards->new('/path/filename' )
    or die $!;

    my $heartbeat;

    while ( $_ = $bw->readline ) {
    /^heartbeat/ and $heartbeat = 1 and next;
    ($heartbeat and /^send/ and print) or $heartbeat = 0;
    }

    --
    Charles DeRykus
    C.DeRykus, Aug 27, 2009
    #7
  8. Tao Li

    Guest

    On Wed, 26 Aug 2009 22:37:31 -0700 (PDT), Tao Li <> wrote:

    >if you can do it with one-liner, that would be wonderful.
    >
    >On Aug 27, 12:36 am, Tao Li <> wrote:
    >> I have been thinking the problem for a while, please help me.
    >>
    >> There is a log file. Its format is like this:
    >>
    >> send ........
    >> send ........
    >> ................
    >> ............
    >> send..........
    >> ...................
    >> ................
    >> send..........
    >> heartbeat..........
    >> ...............
    >> send........
    >> ...........
    >> .........
    >> send..........
    >> send.........
    >> send..........
    >> heartbeat..........
    >> ....
    >> send...
    >> .....
    >> heatbeat....
    >> ....
    >>
    >> I want to find all the "send line" before "heartbeat line"?
    >>
    >> send...
    >> send...
    >> heartbeat...
    >>
    >> doesn't include anything like this:
    >>
    >> send...
    >> .....
    >> send...
    >> heartbeat..........


    print "\n",$cnt++,"\n",@{[split /send/]},"\n" for $data=~/((?:^send.*?\n)+(?=heartbeat))/mg;

    -sln
    , Aug 27, 2009
    #8
  9. "C.DeRykus" <> wrote:
    >On Aug 26, 10:36 pm, Tao Li <> wrote:
    >> There is a log file. Its format is like this:

    [...]
    >> I want to find all the "send line" before "heartbeat line"?

    >
    >If you don't mind capturing hits from the bottom of the
    >log first, you could use File::ReadBackwards (which is o
    >ften useful for reading logfiles):


    Neat idea!

    And if the sequence is important and the hit list not too large, then he
    could store all hits in an array and then reverse() the array before
    printing it. Or printing the array from the rear.

    jue
    Jürgen Exner, Aug 28, 2009
    #9
  10. Tao Li

    Tao Li Guest

    Thanks for all of your replies.

    I found the RE solution,

    #!/usr/bin/perl

    undef $/;

    while ( <> ) {

    while ( /(^send(.*)\n)+(^heartbeat(.*)\n)/mg ) {

    print $&;

    }

    }

    However I think John's solution is much more decent. Thank you.



    On Aug 27, 1:18 am, "John W. Krahn" <> wrote:
    > Tao Li wrote:
    > > I have been thinking the problem for a while, please help me.

    >
    > > There is a log file. Its format is like this:

    >
    > > send ........
    > > send ........
    > > ................
    > > ............
    > > send..........
    > > ...................
    > > ................
    > > send..........
    > > heartbeat..........
    > > ...............
    > > send........
    > > ...........
    > > .........
    > > send..........
    > > send.........
    > > send..........
    > > heartbeat..........
    > > ....
    > > send...
    > > .....
    > > heatbeat....
    > > ....

    >
    > > I want to find all the "send line" before "heartbeat line",

    >
    > > send...
    > > send...
    > > heartbeat...

    >
    > > doesn't include anything like this:

    >
    > > send...
    > > .....
    > > send...
    > > heartbeat..........

    >
    > perl -ne'
    > if ( /^send/ ) { push @buff, $_ }
    > elsif ( /^heartbeat/ ) { print @buff, $_ }
    > else { @buff = () }
    > '
    >
    > John
    > --
    > Those people who think they know everything are a great
    > annoyance to those of us who do. -- Isaac Asimov
    Tao Li, Aug 28, 2009
    #10
  11. Tao Li

    Uri Guttman Guest

    >>>>> "JE" == Jürgen Exner <> writes:

    JE> "C.DeRykus" <> wrote:
    >> On Aug 26, 10:36 pm, Tao Li <> wrote:
    >>> There is a log file. Its format is like this:

    JE> [...]
    >>> I want to find all the "send line" before "heartbeat line"?

    >>
    >> If you don't mind capturing hits from the bottom of the
    >> log first, you could use File::ReadBackwards (which is o
    >> ften useful for reading logfiles):


    JE> Neat idea!

    JE> And if the sequence is important and the hit list not too large, then he
    JE> could store all hits in an array and then reverse() the array before
    JE> printing it. Or printing the array from the rear.

    why reverse? instead of pushing, use unshift.

    uri (author of File::ReadBackwards).

    PS. amusing that i still have never used that module but it is popular!


    --
    Uri Guttman ------ -------- http://www.sysarch.com --
    ----- Perl Code Review , Architecture, Development, Training, Support ------
    --------- Gourmet Hot Cocoa Mix ---- http://bestfriendscocoa.com ---------
    Uri Guttman, Aug 28, 2009
    #11
  12. Tao Li

    Uri Guttman Guest

    >>>>> "TL" == Tao Li <> writes:

    TL> Thanks for all of your replies.
    TL> I found the RE solution,

    TL> undef $/;

    bah!

    TL> while ( <> ) {

    that while is useless as it just reads the whole file into $_ the first time.

    TL> while ( /(^send(.*)\n)+(^heartbeat(.*)\n)/mg ) {

    don't grab when you mean to only group.

    TL> print $&;

    learn about why $& is bad for your perl speed.

    you wanted a one liner.

    (untested)

    use File::Slurp ;

    print read_file( shift @ARGV ) =~ /((?:^send.*)\n)+^heartbeat.*\n)/mg ;

    uri

    --
    Uri Guttman ------ -------- http://www.sysarch.com --
    ----- Perl Code Review , Architecture, Development, Training, Support ------
    --------- Gourmet Hot Cocoa Mix ---- http://bestfriendscocoa.com ---------
    Uri Guttman, Aug 28, 2009
    #12
  13. "Uri Guttman" <> wrote:
    >>>>>> "JE" == Jürgen Exner <> writes:

    >
    > JE> "C.DeRykus" <> wrote:
    > >> On Aug 26, 10:36 pm, Tao Li <> wrote:
    > >>> There is a log file. Its format is like this:

    > JE> [...]
    > >>> I want to find all the "send line" before "heartbeat line"?
    > >>
    > >> If you don't mind capturing hits from the bottom of the
    > >> log first, you could use File::ReadBackwards (which is o
    > >> ften useful for reading logfiles):

    >
    > JE> Neat idea!
    >
    > JE> And if the sequence is important and the hit list not too large, then he
    > JE> could store all hits in an array and then reverse() the array before
    > JE> printing it. Or printing the array from the rear.
    >
    >why reverse? instead of pushing, use unshift.


    True, that's even better.

    jue
    Jürgen Exner, Aug 28, 2009
    #13
  14. Tad J McClellan wrote:
    > Tao Li <> wrote:
    >
    >> undef $/;
    >>
    >> while ( <> ) {

    >
    >
    > How many iterations to you expect from that loop?


    Depends on how many file names are in @ARGV. :)



    John
    --
    Those people who think they know everything are a great
    annoyance to those of us who do. -- Isaac Asimov
    John W. Krahn, Aug 28, 2009
    #14
  15. Tao Li

    C.DeRykus Guest

    On Aug 27, 4:27 pm, Jürgen Exner <> wrote:
    > "C.DeRykus" <> wrote:
    > >On Aug 26, 10:36 pm, Tao Li <> wrote:
    > >> There is a log file. Its format is like this:

    > [...]
    > >> I want to find all the "send line" before "heartbeat line"?

    >
    > >If you don't mind capturing hits from the bottom of the
    > >log first, you could use File::ReadBackwards (which is o
    > >ften useful for reading logfiles):

    >
    > Neat idea!
    >
    > And if the sequence is important and the hit list not too large, then he
    > could store all hits in an array and then reverse() the array before
    > printing it. Or printing the array from the rear.


    Thanks, I've found Uri's module useful several times.

    --
    Charles DeRykus
    C.DeRykus, Aug 28, 2009
    #15
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Anand

    Regular Expression help...

    Anand, Jul 9, 2003, in forum: Perl
    Replies:
    1
    Views:
    1,221
    Eric J. Roode
    Jul 9, 2003
  2. Eric B.
    Replies:
    1
    Views:
    428
    Jim Gibson
    Dec 17, 2004
  3. VSK
    Replies:
    2
    Views:
    2,272
  4. =?iso-8859-1?B?bW9vcJk=?=

    Matching abitrary expression in a regular expression

    =?iso-8859-1?B?bW9vcJk=?=, Dec 1, 2005, in forum: Java
    Replies:
    8
    Views:
    832
    Alan Moore
    Dec 2, 2005
  5. GIMME
    Replies:
    3
    Views:
    11,924
    vforvikash
    Dec 29, 2008
Loading...

Share This Page