tags:

views:

182

answers:

6

Hello,

i have got a simple problem :( I need to replace text smilies with the according smiley-image. ok.. thats not really complex, but now i have to replace only smilie appereances outside of HTML Tags. short examplae:

Text:

Thats a good example :/ .. with a <a href="http://www.foobar.com"&gt;link&lt;/a&gt; inside.

i want to replace ":/" with the image of this smiley...

ok, how to do that the best way?

A: 

I wouldn't know about the best way, only the way I would do it.

Build an array having the smiley codes as the keys and the link as the value. The use str_replace. Pass as "needle" an array of the keys (the smiley codes) and as "replace" an array of the values.

For instance, suppose you have something like this:

$smiley_array = array(":)" => "<a href...>",
    ":(" => "<a href=....>");
$codes = array_keys($smiley_array);
$links = array_values($smiley_array);
$str = str_replace($codes, $links, $str);

EDIT: In case this could accidentally replace other instances with smiley-links you should consider using regexes with preg_replace. Obviously preg_replace is slower than str_replace.

nc3b
sorry, maybe i did not describe the problem so far... the problem is, by replacing ":/" with an image, the ":/" of "http://" will be matched too, then i would get something like this:<a href="http<img .../>/www.foobar.com
michaelm
Consider using regexes
nc3b
A: 

You can use regex, or the extra sloppy version of the above:

$smiley_array = array(":)" => "<a href...>",
    ":(" => "<a href=....>");
$codes = array_keys($smiley_array);
$links = array_values($smiley_array);
$str = str_replace("://", "%%QF%%", $str);
$str = str_replace($codes, $links, $str);
$str = str_replace("%%QF%%", "://", $str);

Actually, assuming str_replace follows the array sorting... this should work:

$smiley_array = array("://" => "%%QF%%", ":)" => "<a href...>",
    ":(" => "<a href=....>", "%%QF%%" => "://");
$codes = array_keys($smiley_array);
$links = array_values($smiley_array);
$str = str_replace($codes, $links, $str);
A: 

Possible overkill (increased cpu/load), but 99.99999999% safe:

<?php
$n = new DOMDocument();
$n->loadHTML('<p>Thats a good example :/ .. with a <a href="http://www.foobar.com"&gt;link&lt;/a&gt; inside.</p>');
$x = new DOMXPath($n);
$instances = $x->query('//text()[contains(.,\':/\')]');//or use '//*[child::text()]' for all textnodes
foreach($instances as $node){
    if($node instanceof DOMText && preg_match_all('/:\//',$node->wholeText,$matches,PREG_OFFSET_CAPTURE|PREG_SET_ORDER)){
            foreach($matches[0] as $match){
                    $newnode = $node->splitText($match[1]);
                    $newnode->replaceData(0,strlen($match[0]),'');
                    $img = $n->createElement('img');
                    $img->setAttribute('src','smily.gif');
                    $img = $newnode->parentNode->insertBefore($img,$newnode);
                    //var_dump($match);
            }
    }
}
var_dump($n->saveHTML());
?>

But in reality you do not want to do this all that often, save once, show many, if you are letting users edit the html (beit in wysiwyg or elsewise, the 'return' transformation (img to text) is a whole lot lighter. Up to you to expand with different smilies (one monster regex to match them, or several smaller ones / strstr()'s for readability, and a array for smiley to src (e.g. array(':/'=>'frown.gif')) would be the way to go.

Wrikken
+1  A: 

I won't try to create some super script but think about it.... smilies are just about always surrounded by spaces. So str replace ' :/ ' with the smiley. You could be saying "what about a smiley at the end of a sentence(where it would be used the most)". Well just check for at least one space on either the left or the right of a potential smiley.

Using the above scripts:

$smiley_array = array(
    ":) " => "<a href...>",
    " :)" => "<a href...>",
    ":/ " => "<a href...>",
    " :/" => "<a href...>");
$codes = array_keys($smiley_array);
$links = array_values($smiley_array);
$str = str_replace($codes, $links, $str);

If you rather not have to type everything twice you can generate the array from a single smiley array.

Michael Ozeryansky
A: 

Why don't you just try to use some special chars around your smiley text like this maybe -:/- This will make your smiley text some kind of unique and easy to recognize

Coder_
+1  A: 

Use preg_replace with a lookbehind assertion. Example:

$smileys = array(
  ':/' => '<img src="..." alt=":/">'
);
foreach ($smileys as $smile => $img) {
  $text = preg_replace('@(?<!<[^<>]*)' . preg_quote($smile, '@') . '@',
                       $img, $text);
}

The regex should match only smileys that are not inside angle brackets. This might be slow if you have a lot of false positives.

Krzysztof Kosiński