#!/usr/bin/perl use strict; use warnings; die "No search terms supplied!" unless @ARGV; my @words = @ARGV; my $text; { local $/ = undef; $text = ; } my $regex = join ( "|", @words ); # Words to highlight my $expr = qr /(?i)($regex)/; # Compile regex my $glen = 20; # Characters before and after the end of match to grab. { no warnings 'uninitialized'; my ( $ls, $le, @results ); # $ls=prev span start, $le=prev span end, @results, results destination # Markup any matches or exit block. last unless $text =~ s/\b($expr)\b/[$1]/gi; while ( $text =~ m/\b($expr)\b/sg or $le <= length ($text) ) { my ($ipos,$spos,$epos); # char span positions if ($ipos = pos($text)) { # If the last match succeded $spos = $ipos - $glen > 0 ? $ipos - $glen : 0; # Range check $epos = $ipos + $glen < length($text) ? $ipos + $glen : length($text); # Assign to ($ls,$le) if this is our first time through and next. ( $ls, $le ) = ( $spos, $epos ) and next unless $le; } if ( $spos and $spos < $le ) { # If we have a match and it intersects the last match $le = $epos; # merge overlapping char spans } else { # Lose the first word(possible fragment) unless the match is the first word. $ls = index($text," ", $ls) + 1 unless ($ls == 0); push @results,substr( $text, $ls, $le - $ls ) ; ( $ls, $le ) = ( $spos, $epos ); # Set "last position" to current. } last unless defined $spos; # End unless we have one more match } print '"',$_,'..."', "\n" foreach @results; } __DATA__ Regular expressions have always been a weak spot for me, and I've got a question that's got me stumped. Here's the problem I'm trying to solve. I have somewhat large articles of text (returned from a search), what I'd like to do is capture the word and X number of words before and after it while tagging the matching word in the captured text. My inital thought was to try something like this. The problem I have is that if there is more than one term and they overlap, the nth term will not be annotated. So my next thought is lookahead/lookbehind, but they don't capture. Is there a way to do this with a single regex? Is a regex even the best way to do this? Thanks, -Lee