0

I am relatively new to php, and hope someone can help me with a replace regex, or maybe a match replace I am not exactly sure.

I want to automatically bold the (second occurance of a match) and then make the 4th appearance of a match italic and then the 7th appearance of a match underlined.

This is basically for SEO purposes in content.

I have done some replacements with: and were thinking this should do the trick?

preg_replace( pattern, replacement, subject [, limit ])

I already know the word I want to use in

'pattern' is also a word that is already defined like [word].
`replacement` 'This is a variable I am getting from a mysql db.
'subject' - The subject is text from a db.

Lets say I have this content: This explains more or less what I want to do.

This is an example of the text that I want to replace. In this text I want to make the second occurance of the word example < bold. Then I want to skip the next time example occurs in the text, and make the 4th time the word example appears in italic. Then I want to skip the 5th time the word example appears in the text, as well as the 6th time and lastly wants to make the 7th time example appears in the text underline it. In this example I have used a hyperlink as the underline example as I do not see an underline function in the text editor. The word example may appear more times in the text, but my only requerement is to underline once, make bold once and make italic once. I may later descide to do some quotes on the word "example" as well but it is not yet priority.

It is also important for the code not to through an error if there is not atleast 7 occurances of the word.

How would I do this, any ideas would be appreciated.

Gerald Ferreira
  • 1,349
  • 2
  • 23
  • 44

3 Answers3

3

The regular expression itself cannot count, and the preg_ functions provide little help. You need a workaround. If you were to actually search for just a word, you might want to use string functions. Otherwise try:

// just counting
if (7 >= preg_match_all($pattern, $subject, $matches)) {

   $cb_num = 0;
   $subject = preg_replace_callback($pattern, "cb_ibu", $subject);
}

function cb_ibu($match) {
    global $cb_num;

    $match = $match[0];

    switch (++$cb_num) {
        case 2: return "<b>$match</b>";
        case 4: return "<i>$match</i>";
        case 7: return "<u>$match</u>";
        default: return $match;
    }
}

The trick is to have a callback which does the accounting. And there it's quite easy to add any rules.

mario
  • 144,265
  • 20
  • 237
  • 291
  • Thanks Mario, I am checking this now... just to make sure – Gerald Ferreira Apr 16 '11 at 15:36
  • $pattern = '/\[word\]/' $subject = ?, $matches = ? I am not sure what to put in subject and matches... – Gerald Ferreira Apr 16 '11 at 15:36
  • The `$matches` is just an unused throwaway variable there. But `$subject` is your source text. – mario Apr 16 '11 at 15:38
  • I have implemented it like this... $pattern = '/'.$g_page_identify.'/'; $subject = $g_page_content2; // just counting if (7 >= preg_match_all($pattern, $subject, $matches)) { $cb_num = 0; $subject = preg_replace_callback($pattern, "cb_ibu", $subject); } function cb_ibu($match) { global $cb_num; $match = $match[0]; switch (++$cb_num) { case 2: return "$match"; case 4: return "$match"; case 7: return "$match"; default: return $match; } } – Gerald Ferreira Apr 16 '11 at 15:43
  • Thanks for the feedback mario, I appreciat it, I have eventually gone for the solution provided by Gumbo – Gerald Ferreira Apr 16 '11 at 18:22
  • @Gerald: A good choice too. It's most likely more speedy. And quite compact and workable for your case. – mario Apr 16 '11 at 18:23
3

You could use preg_split to split the text at the matches, apply the modifications, and then put everything back together:

$parts = preg_split('/(example)/', $str, 7, PREG_SPLIT_DELIM_CAPTURE);
if (isset($parts[3])) $parts[3] = '<b>'.$parts[3].'</b>';
if (isset($parts[7])) $parts[7] = '<i>'.$parts[7].'</i>';
if (isset($parts[13])) $parts[13] = '<u>'.$parts[13].'</u>';
$str = implode('', $parts);

The index formula for the i-th match is index = i · 2 - 1.

Gumbo
  • 643,351
  • 109
  • 780
  • 844
  • Thanks Gumbo! I can almost just start sending all my questions directly to you :-) most of the time you are the one with the answers that works! Thanks a million. – Gerald Ferreira Apr 16 '11 at 18:23
  • Hi Gumbo now I am totally confused. I have used the code on this page http://24hour-casino-games.com/casino-reviews/online/casino_may_flower.asp the h1 is not part of the string. So if I count the "May Flower Casino" words. The 2nd may flower casino gets highlighted, which is correct. Then the 4th time it is used it is in italic - which is correct. and then if I make the value after $str, 7 (14) it shows another bold at position 7 which is correct. can you please explain to me how come $parts[7] shows at position 4 and $parts[13] at position 7... Thanks – Gerald Ferreira Apr 16 '11 at 19:20
  • 1
    @Gerald Ferreira: When `preg_split` captures the delimiter (the match of the pattern), the result is always an odd number of parts where every even part with an odd index (since zero-based) is a delimiter. So the first delimiter is at 1, the second at 3, the third at 5, etc. And this can be expressed with *i* · 2 - 1. – Gumbo Apr 16 '11 at 19:26
  • ok - now it makes sence thanks Gumbo. I have now increased the number with 1 - then it select all the text between May Flower and May Flower, and if I make if odd again it selects the word! - Thank you very much for the help - this is an excellent solution! - I see underline has been depreciated so I am going to go with a link rather... – Gerald Ferreira Apr 16 '11 at 19:34
0

That's an interesting question. My implementation would be:

function replace_exact($word, $tag, $string, $limit) {
    $tag1 = '<'.$tag.'>';
    $tag2 = '</'.$tag.'>';
    $string = str_replace($word, $tag1.$word.$tag2, $string, 1);
    if ($limit==1) return $string;
    return str_replace($tag1.$word.$tag2,$word,$string,$limit-1);
}

Use it like this:

echo replace_exact('Example', 'b', $source_text, 2);
echo replace_exact('Example', 'i', $source_text, 4);

I don't know about how fast this will work, but it will be faster than preg_replace.

Alexander Ivanov
  • 717
  • 4
  • 16