help on regular expression

T

Tao Li

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..........
 
J

John W. Krahn

Tao said:
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
 
R

Randal L. Schwartz

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
 
C

ccc31807

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
 
J

Jürgen Exner

ccc31807 said:
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
 
C

C.DeRykus

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;
}
 
J

Jürgen Exner

C.DeRykus said:
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
 
T

Tao Li

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.
 
U

Uri Guttman

JE> "C.DeRykus said:
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!
 
U

Uri Guttman

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
 
J

Jürgen Exner

Uri Guttman said:
JE> "C.DeRykus said:
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
 
C

C.DeRykus

C.DeRykus said:
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.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,046
Latest member
Gavizuho

Latest Threads

Top