Need Help with Php array problem

Yesterday I hurriedly finished solving a user’s problem and uploaded the rough answer. I am convinced there must be a more elegant solution to handle $sColor than the following:

// associate color with search word
  foreach( $aSrchs as $id => $sSrc):
    $x[$sSrc] = $aClrs[$id];
    $y[ $aClrs[$id] ] = $sSrc;
  endforeach;  
  // fred($x, '$x');

// step through $aWords
  $aResult = [];
  foreach( $aWords as $word ): // Say ye to the righteous
    if( $i2=in_array($word, $y) ):
      $sColor = $x[ $word ]; // integer
      $aResult[] = '<b style="color:' .$sColor .';">'  .$word  .'</b>';      
    else:
      $aResult[] = $word;      
    endif;  
  endforeach;

Complete solution can be found here:
Online Demo

I would be grateful for more succinct solutions.

Edit
iPad mini 2 rendering is horrible and will rectify when back on the desktop.

1 Like

This is my stab at it. It recycles the colors that is assigned to the words when the number of matched words is greater than the colors available.

<?php
function highlight($text, array $words, array $colors, $ignoreCase = false, $format = '<b style="color:%s">%s</b>')
{
    $wordToColor = [];
    $colorIdx = 0;

    $re = '~\\b('.implode('|', $words).')\\b~';
    if ($ignoreCase) {
        $re .= 'i';
    }

    return preg_replace_callback($re, function ($m) use ($colors, $format, &$wordToColor, &$colorIdx) {
        $word = $m[0];

        if (!isset($wordToColor[$word])) {
            $wordToColor[$word] = $colors[$colorIdx];
        }
        $colorIdx = $colorIdx < count($colors) - 1 ? $colorIdx + 1 : 0;

        $color = $wordToColor[$word];

        return sprintf($format, $color, $word);
    }, $text);
}

$text = "I've seen things you people wouldn't believe. Attack ships on fire off the shoulder of Orion. I watched C-beams glitter in the dark near the Tannhäuser Gate. All those moments will be lost in time, like tears...in...rain. Time to die.";
$words = ['tannhäuser', 'orion', 'fire', 'tears', 'rain' ,'die'];
$colors = ['red', 'green', 'blue'];
$format = '<span style="color:%s;">%s</span>';

$hl = highlight($text, $words, $colors, true, $format);

echo <<< EOF_HTML
  <!doctype html>
  <html>
    <head>
      <meta charset="utf-8">
      <title>Highlight</title>
    </head>
    <body>
      <p>$hl</p>
    </body>
  </html>
EOF_HTML;

Many thanks for the script, ìt looks good and I look forward to trying it tomorrow.

This morning I had another attempt and made a much cleaner version which I uploaded and the modifications can be seen in the latest version.

@davidtsadler

Updated Link

Edit:
I have tried to understand your function but it seems far too complicated for my liking :frowning:

function highlight(
  string $text, 
  array  $words, 
  array  $colors, 
  bool   $ignoreCase = false, 
  string $format     = '<b style="color:%s">%s</b>'
):string
{
    $wordToColor = [];
    $colorIdx = 0;

    $re = '~\\b('.implode('|', $words).')\\b~';
    if ($ignoreCase) {
        $re .= 'i';
    }

    return preg_replace_callback
    (
      $re, 
      function ($m) use 
      (
        $colors, $format, &$wordToColor, &$colorIdx
      ):string
      {
        $word = $m[0];

        if ( ! isset($wordToColor[$word]) ) {
            $wordToColor[$word] = $colors[$colorIdx];
        }
        $colorIdx = $colorIdx < count($colors) - 1 ? $colorIdx + 1 : 0;

        $color = $wordToColor[$word];

        return sprintf($format, $color, $word);
      },
      $text
    );
}

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.