14

I have an array with:

emoticons = {
   ':-)' : 'smile1.gif',
   ':)'  : 'smile2.gif',
   ':D'  : 'smile3.gif'     
}

then i have a variabile with the text.

var text = 'this is a simple test :)';

and a variable with the url of the website

var url = "http://www.domain.com/";

How to write a function that replace the symbols with their images?

The <img> tag result should be:

<img src="http://www.domain.com/simple2.gif" />

(I have to concatenate the url varible to the name of the image).

THank you very much!

Maksym Gontar
  • 22,765
  • 10
  • 78
  • 114
Damiano
  • 149
  • 1
  • 1
  • 3

3 Answers3

33

Another approach:

function replaceEmoticons(text) {
  var emoticons = {
    ':-)' : 'smile1.gif',
    ':)'  : 'smile2.gif',
    ':D'  : 'smile3.gif'
  }, url = "http://www.domain.com/";
  // a simple regex to match the characters used in the emoticons
  return text.replace(/[:\-)D]+/g, function (match) {
    return typeof emoticons[match] != 'undefined' ?
           '<img src="'+url+emoticons[match]+'"/>' :
           match;
  });
}

replaceEmoticons('this is a simple test :)');
// "this is a simple test <img src="http://www.domain.com/smile2.gif"/>"

Edit: @pepkin88 made a really good suggestion, build the regular expression based on the property names of the emoticons object.

It can be easily done, but we have to escape meta-characters if we want this to work properly.

The escaped patterns are stored on an array, that is later used to build the regular expression using the RegExp constructor, by basically joining all the patterns separated with the | metacharacter.

function replaceEmoticons(text) {
  var emoticons = {
    ':-)' : 'smile1.gif',
    ':)'  : 'smile2.gif',
    ':D'  : 'smile3.gif',
    ':-|'  : 'smile4.gif'
  }, url = "http://www.domain.com/", patterns = [],
     metachars = /[[\]{}()*+?.\\|^$\-,&#\s]/g;

  // build a regex pattern for each defined property
  for (var i in emoticons) {
    if (emoticons.hasOwnProperty(i)){ // escape metacharacters
      patterns.push('('+i.replace(metachars, "\\$&")+')');
    }
  }

  // build the regular expression and replace
  return text.replace(new RegExp(patterns.join('|'),'g'), function (match) {
    return typeof emoticons[match] != 'undefined' ?
           '<img src="'+url+emoticons[match]+'"/>' :
           match;
  });
}

replaceEmoticons('this is a simple test :-) :-| :D :)');
Community
  • 1
  • 1
Christian C. Salvadó
  • 807,428
  • 183
  • 922
  • 838
  • 1
    It would be even better if regexp was generated depending on keys values in `emoticons`. – pepkin88 Sep 07 '10 at 15:12
  • 1
    @pepkin88: Great suggestion :), I've added a function that makes this possible. – Christian C. Salvadó Sep 07 '10 at 20:39
  • 1
    This could be further enhanced by closing over the `replace()` (similar to [this answer](http://stackoverflow.com/questions/286921/javascript-efficiently-replace-all-accented-characters-in-a-string/614397#614397)…) - this would accelerate repeated calls to the function. – Tomalak Sep 10 '10 at 15:06
  • @CMS It was great help for one of my applications. – redV Sep 02 '14 at 18:08
  • Awesome answer! Especially the second part :) The first one matches all kind of symbols (like ':', ')' and even 'D'), which I think will be very slow in large amount of text. The second one is great, with a little modification, that @Tomalak suggested - it's not worth to create all patterns every time. Anyways - still great answer! Cheers! :) – Andrey Popov Mar 06 '15 at 09:35
4
for ( smile in emoticons )
{
   text = text.replace(smile, '<img src="' + url + emoticons[smile] + '" />');
}
nothrow
  • 15,882
  • 9
  • 57
  • 104
  • 1
    It won't work correctly since replace replaces only the first ocurrence of the matched string. – mati Jun 16 '10 at 17:10
  • Only works to replace the first occurance of each smiley. In a string like "This is replaced :) but not this :)" the second one is left unchanged. – Guffa Jun 16 '10 at 17:12
  • 1
    Also make sure to use `var` in the `for...in` statement, otherwise if the code is inside a function that doesn't declare the `smile` variable in that scope, it will become global, and using an `if (emoticons.hasOwnProperty(smile))` inside the loop is a good idea. – Christian C. Salvadó Jun 16 '10 at 17:14
  • ok, so how to use .replace() to replace more then one occurence ? – Damiano Jun 16 '10 at 17:22
  • to replace more than one occurrence change `smile` to `new RegExp(smile, 'g')` – pepkin88 Sep 07 '10 at 15:20
  • or you can also /smile/g :P – Jacek Pietal Dec 20 '16 at 17:02
0

Using a regex with an array of find replace elements works well.

var emotes = [
    [':\\\)', 'happy.png'],
    [':\\\(', 'sad.png']
];

function applyEmotesFormat(body){
    for(var i = 0; i < emotes.length; i++){
        body = body.replace(new RegExp(emotes[i][0], 'gi'), '<img src="emotes/' + emotes[i][1] + '">');
    }
    return body;
}
Ben Dauphinee
  • 4,061
  • 8
  • 40
  • 59