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

I am working on a fairly standard program to search a table and display records. There is one feature though that I am having minor problems with. I wanted the program to highlight the search term used in the text that was returned by the search. To do this I wrote the following function:
sub HighlightText { my ($texttosearch,$searchstring,$color)=@_; my $highlighted = "<FONT COLOR='$color'><B>$searchstring</B></FONT> +"; $texttosearch =~ s/$searchstring/$highlighted/gi; return $texttosearch; }
The function seems at first to work perfectly, then I noticed a flaw. If the variable "$searchstring" contains "Foo" and the $texttosearch contains "foo" the search will highlight the text as it should but, because of the way it is written "Foo" now becomes "foo". I need to be able to retain the case of the original text while still being able to search and highlight irregardless of case. I thank you in advance for your help.

Replies are listed 'Best First'.
RE: Search Term Highlighting
by sean (Beadle) on Jun 14, 2000 at 19:11 UTC
    $texttosearch =~ s:($searchstring):<FONT COLOR="$color">$1</FONT>:ig;
    should work..
      Thank You that worked perfectly!
RE: Search Term Highlighting
by muppetBoy (Pilgrim) on Jun 14, 2000 at 18:46 UTC
    A simple solution may be:
    $texttosearch =~ s/$searchstring/"<FONT COLOR='$color'><B>$searchstrin +g<\/B><\/FONT>/gi;
    Which just combines two lines of your code. Note the escaped /s in the regular expression.
    In fact, thinking about it, ditch the subroutine as this is a one line solution.
    Update: Oops, as has been pointed out in the replies below, the () and $1 method is the way preserve the case. Should have checked my code I guess.
      This doesnt seem like it is any different from my code except that it is on one line. The problem is that if $searchstring contains "foo" and $texttosearch contains "Foo" (note the case difference) when the replace occurs $texttosearch now contains "foo" instead of "Foo". The code provided by sean does however solve the problem. Thanks for your suggestion though.
Re: Search Term Highlighting
by gnat (Beadle) on Jun 14, 2000 at 22:35 UTC
    If you have an array of search terms, you can highlight any one of them with:
    $re = join "|", map {quotemeta} @term;
    $results = s{($re)}{$1}ig;
    
    That's just a simple extension of sean's code. If your search terms are regexps and not plain strings, then do without the mapping of quotemeta.
RE: Search Term Highlighting
by Anonymous Monk on Jun 15, 2000 at 02:09 UTC
    Modify your regular expression from /gi to /i
      That will find and highlight only the first match, then move on to the next line of code. It appears the OP wants to highlight *all* of the search terms in the document while preserving case.

      The secret, as my fellow monks have pointed out, is using parenthesis to collect the match on the left hand side of the substitution and the special variable $1 to insert that match on the right hand side. Read more about it in perlre.

      (Yes, code needs explanation of the mechanics, sometimes.)

        Thank you for explaining how that works, I was curious but though I would try looking it up first, then ask if i couldnt figure it out myself. Now you saved me the trouble :-)