( $match )= $string =~ /($pattern)/;
####
package Stream::Match;
sub new {
my( $class, $stream, $pattern )= @_;
return bless {
str => $stream, # Stream to read from
pat => $pattern, # Regex to find matches
buf => "", # Stream data that might match later
blk => 8*1024, # How many bytes to read each time
}, $class;
}
sub nextMatch {
my( $self )= @_;
my $svBuf= \$self->{buf};
pos( $$svBuf )= 0; # Just in case
my $res= 1;
while( 1 ) {
if( $res && length($$svBuf) < $self->{blk} ) {
# Append more data from stream to $self->{buf}:
$res= sysread( $self->{str}, $$svBuf,
$self->{blk}, length($$svBuf) );
if( ! defined $res ) {
die "Error reading from stream ($self->{str}): $!";
}
}
if( "" eq $$svBuf ) {
return; # End of file
}
# Note that 0 == pos( $$svBuf )
my $match= $res
? $$svBuf =~ /$self->{pat}/zg
: $$svBuf =~ /$self->{pat}/g;
if( $match ) { # We got a match!
# Copy the match (like $&):
my $line= substr( $$svBuf, $-[0], $+[0]-$-[0] );
# Leave only $' in $self->{buf}:
substr( $$svBuf, 0, $+[0], "" );
return $line;
}
my $pos= pos( $$svBuf );
if( ! defined $pos ) { # Didn't hit end-of-string:
return; # This regex will NEVER match.
}
# Remove $self->{buf} chars that will never start a match:
substr( $$svBuf, 0, $pos, "" );
}
}
package main;
# Sample use that emulates the Unix "strings" command:
binmode( STDIN );
my $o= Stream::Match->new( \*STDIN, qr/[\s -~]+(?=\0)/ );
my $string;
while( $string= $o->nextMatch() ) {
print "$string\n";
}
##
##
__END__
# This is the code I originally posted
package Stream::Match;
sub new {
my( $class, $stream, $pattern )= @_;
return bless {
str => $stream, # Stream to read from
pat => $pattern, # Regex to find matches
buf => "", # Stream data that might match later
blk => 8*1024, # How many bytes to read each time
}, $class;
}
sub nextMatch {
my( $self )= @_;
my $svBuf= \$self->{buf};
my $res;
do {
# Note that 0 == pos( $$svBuf )
if( $$svBuf =~ /$self->{pat}/zg ) { # We got a match!
# Copy the match (like $&):
my $line= substr( $$svBuf, $-[0], $+[0]-$-[0] );
# Leave only $' in $self->{buf}:
substr( $$svBuf, 0, $+[0], "" );
return $line;
}
my $pos= pos( $$svBuf );
if( ! defined $pos ) { # Didn't read end-of-string:
return; # This regex will NEVER match.
}
# Remove $self->{buf} chars that will never start a match:
substr( $$svBuf, 0, $pos, "" );
# Append more data from stream to $self->{buf}:
$res= sysread(
$self->{str}, $$svBuf, $self->{blk}, length($$svBuf) );
} while( $res );
if( ! defined $res ) {
die "Error reading from stream ($self->{str}): $!";
}
return; # End of file
}
package main;
# Sample use that emulates the Unix "strings" command:
binmode( STDIN );
my $o= Stream::Match->new( \*STDIN, qr/[\s -~]+(?=\0)/ );
my $string;
while( $string= $o->nextMatch() ) {
print "$string\n";
}