Based on your requirements, here is what I came up with:
// needs to be global given that you are using non-anonymous function syntax
$count = 0;
function repWords($content) {
global $count;
$words_array = array('some','content','foobar');
foreach ($words_array as $w) {
$pattern = '~\b('.$w.'s?)\b~';
$count=0;
preg_match_all($pattern,$content,$matches);
$count=count($matches[0]);
if ($count>0)
$content = preg_replace_callback($pattern,'addHtml',$content);
}
return $content;
}
function addHtml ($format) {
global $count;
static $cc=1;
static $pf='';
$val=$format[1];
$cc = ($pf!=$val) ? 1 : ++$cc;
if ((1==$count)||($cc==($count-1)))
$format[1]= '<span>' . $val . '</span>';
$pf=$val;
return $format[1];
}
$content = <<<EOC
this is some content
some more content
this content foobar
EOC;
echo repWords($content);
output
this is <span>some</span> content
some more <span>content</span>
this content <span>foobar</span>
- the first "some" is wrapped because there are 2 instances of it
- the 2nd "content" is wrapped because there are 3 instances of it
- "foobar" is wrapped because there is only 1 instance of it
Note: this utilizes a global variable $count
. In general, it's a bad idea to use global variables. But this is one of the few examples where it's grudgingly accepted, due to limitation of php and preg_replace_callback
(or any function that you can specify a callback) when you opt to define the callback separately instead of use an anonymous function. If you are on php5.3+ and are willing to make addHtml
an anonymous function instead, $count
can be passed to the anonymous function with use
. Alternatively, if all this is actually in a class, make it a class property and use $this->count
instead.
Another note: The very last thing you said was "(not always the first occurrence)" I was somewhat confused by this and took it to possibly mean that you want to somehow be able to specify the nth* instead of it always being "2nd to last (or first if there's only 1" e.g. in my code example perhaps you want to change it to be every 3rd to last word instead of 2nd to last. I asked you to clarify but you didn't respond by the time I posted this solution, so I did not write the code to be flexible for that. However, hopefully you should be able to take this and alter it to suit you if that's what you want. Basically it will involve passing another arg to repWords
and it will also involve using another global variable to use in addHtml
, where $cc==($count-1)
is used.