Something important. Something less important. More important stuff. Just some trivia.more tags"; // Send the pieces array to JS. $pieces = preg_split('/(<[^>]+>)/', $string, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_OFFSET_CAPTURE); $stripped = "Plain text.Something important. Something less important. More important stuff. Just some trivia.more tags"; $search = 'important stuff. Just '; $found_begin = strpos($stripped, $search); $search_length = strlen($search); $found_end = $found_begin + $search_length; $return = ''; $tag = FALSE; $highlight = FALSE; $first_chunk = FALSE; $tag_length = 0; foreach ($pieces as $piece) { list($chunk, $start_of_chunk) = $piece; $length_of_chunk = strlen($chunk); $end_of_chunk = $start_of_chunk + $length_of_chunk; // We find the start and the end of the chunk in the stripped string. $start_of_chunk_in_stripped = $start_of_chunk - $tag_length; $end_of_chunk_in_stripped = $end_of_chunk - $tag_length; if ($tag) { // We calculate the offset between the stripped and the original. $tag_length += $length_of_chunk; } else { if ($start_of_chunk_in_stripped <= $found_begin && $found_begin < $end_of_chunk_in_stripped) { $highlight = TRUE; $first_chunk = TRUE; } if ($highlight) { $last_chunk = $found_end <= $end_of_chunk_in_stripped; if ($last_chunk) { $highlight = FALSE; } $prefix = $postfix = ''; $start = 0; $length = $length_of_chunk; $substr = FALSE; if ($first_chunk) { $start = $found_begin - $start_of_chunk_in_stripped; $prefix = substr($chunk, 0, $start); // The first_chunk always uses the search_length -- if it is also the // last chunk, that's exactly the number of characters we need, if it // is not the last chunk then we try to highlight more characters than // there is in the chunk which means that we highlight the rest of the // chunk. $length = $search_length; $substr = TRUE; } if ($last_chunk) { if (!$first_chunk) { // We begin highlighting at the start of the chunk (in the stripped // string) and finish where the found string ends. $length = $found_end - $start_of_chunk_in_stripped; } // We are not highlighting the rest. $postfix = substr($chunk, $start + $length, $length_of_chunk); $substr = TRUE; } // Only run the substr when necessary. $chunk_to_highlight = $substr ? substr($chunk, $start, $length) : $chunk; $chunk = $prefix . '' . $chunk_to_highlight . "" . $postfix; $first_chunk = FALSE; } } $return .= $chunk; $tag = !$tag; } print "\n\n$return\n";