glwtta has asked for the wisdom of the Perl Monks concerning the following question:

Greetings Monks,

I have a very silly problem: I am displaying the results of a search, I have the string searched for and the result string, what I need to do is highlight the query string in the results, but also to put a line break in the result every 80 characters.

So, if I do the breaks I can no longer match the query within the results (since it could have a \n in it) and if I do the markup first, a \n could fall within the 'span' tag.

What I do right now is save the original start index of the query string, insert the breaks, then calculate the number of breaks that would go before it and insert the tags accordingly. Somehow this just doesn't feel very elegant, is there a more perly way?

thanks a lot

Replies are listed 'Best First'.
Re: highlight and line breaks
by Aristotle (Chancellor) on Jan 16, 2003 at 00:29 UTC
    As always in such cases, the answer is "introduce structure". In this case, you can abuse split. my @result = split /($query)/, $source; Then it's just a matter of keeping track of the previous element's tail's length while line-chopping them one after the other as you would do to the single element, and only finally adding highlights to the matches. Untested:
    my ($extra, $tag_it) = (0, 0); my $output = ""; for(@result) { my @line = split /\n/, $_, -1; unshift @line, unpack "A$extra A*", shift @line; @line = map split /(.{80})/, @lines; $extra = 80 - length @line[-1]; $output .= $tag_it ? "<span>$_</span>" : $_ for join "<br />\n", @line; $tag_it = not $tag_it; }

    Makeshifts last the longest.

Re: highlight and line breaks
by sauoq (Abbot) on Jan 16, 2003 at 00:58 UTC

    Add your markup first. Then use something like the following to add your "linebreaks" (which I gather are newlines from reading your problem description):

    s!((?:<span>|</span>|.){80})!$1\n!g;
    That will allow you to treat your markup tags as a single character when trying to decide where to put your newlines. You may need the /s modifier to deal with existing newlines.

    Edit: Fixed thinko. I meant /s rather than /m of course.

    -sauoq
    "My two cents aren't worth a dime.";
    
      this sounds more like the one-liner I was looking for, but the only problem is that a single character is not good enough, the tags have to be zero characters long for the wrapping purposes.

      thanks for all the great replies though, I am well impressed

        the tags have to be zero characters long for the wrapping purposes.

        That's more difficult. I would probably do it like this:

        $_ = "foo<span>bar</span>bazqux<span>quux</span>"; my $c=0; s( (<span>|</span>|.) ) { my $s = $1; $s =~ m!</?span>! ? $s : $s . (++$c % 4 ? '' : "\n"); }sxge; print; print "\n";

        That will show you how it works but in your case you'll need to change that '4' to '80' in the ++$c % 4 part.

        Update: added /s to regex so . would match "\n" as well.

        -sauoq
        "My two cents aren't worth a dime.";
        
Re: highlight and line breaks
by chromatic (Archbishop) on Jan 15, 2003 at 22:44 UTC

    This is awful, but also a bit clever, if untested:

    my $query = 'some text'; my $searchquery = join('\n?', split(//, $query)); $results = s/($searchquery)/highlight($1)/ge;