1

I have a forum and I would like to automatically parse some of the major links. For example, if a user makes a post like this:

You should visit StackOverflow. I found it on Wikipedia.

it would automatically parse it like this:

You should visit <a href="http://stackoverflow.com">StackOverflow</a>. I found it on <a href="http://en.wikipedia.org/wiki/">Wikipedia</a>.

Is this even doable using JavaScript only?

Thanks for assistance. :-)

Ozzy
  • 8,244
  • 7
  • 55
  • 95
MrEinStain
  • 11
  • 5
  • Are you pre-processing the text before you put it in the DOM, or adding these links once the text is alreadyh in the DOM? – T.J. Crowder Apr 25 '12 at 16:51
  • Isn't this simply replacing words with other words? http://www.w3schools.com/jsref/jsref_replace.asp – DanRedux Apr 25 '12 at 16:51
  • There is a pretty semilar question like your's already on StackOverflow: http://stackoverflow.com/questions/119441/highlight-a-word-with-jquery – YMMD Apr 25 '12 at 16:52

4 Answers4

1

If you're pre-processing the text, you can use the replace function with a callback and a regular expression using an alternation:

var str = "You should visit StackOverflow. I found it on Wikipedia.";
str = str.replace(/StackOverflow|Wikipedia|etc/gi, function(m) {
    var href;
    switch (m.toLowerCase()) {
        case "stackoverflow";
            href = "http://stackoverflow.com";
            break;
        case "wikipedia";
            href = "http://en.wikipedia.org";
            break;
        // ...and so on...
    }
    return '<a href="' + href + '">' + m + '</a>';
});

YMMD points out that the above requires defining each keyword twice, which is true. When I've had to do this with a large number of keywords, I've done it by having an object with the keywords as keys, the href values as values, and built the expression dynamically:

// ==== Setup code you presumably do once

// The substitutions -- make sure the keys are in lower case
var substitutions = {
    "stackoverflow": "http://stackoverflow.com",
    "wikipedia":     "http://en.wikipedia.org",
    // ...and so on...
};

// Build the regex. Here I've used `Object.keys` which is an ES5 feature
// but you can use an ES5 shim (since it's something a shim can provide).
// Note that if your keywords include any special regular expression
// characters, you'll have to loop through the keys manually and escape
// those.
var subrex = new RegExp(Object.keys(substitutions).join("|"), "gi");

// ==== Where you're using it
var str = "You should visit StackOverflow. I found it on Wikipedia.";
str = str.replace(subrex, function(m) {
    return '<a href="' + substitutions[m.toLowerCase()] + '">' + m + '</a>';
});

Live example | source

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • This is IMHO not ideal, because you have to define the keywords twice. There is definitely a better way to achieve this. – YMMD Apr 25 '12 at 16:56
  • @YMMD: You don't *have* to, you can do what I've done before and start with a hash and build the regex dynamically. I'll add an example. *edit* Done – T.J. Crowder Apr 25 '12 at 16:57
  • To me this seems a great deal better. :-) Thanks for updating your answer! – YMMD Apr 25 '12 at 17:05
  • When I try in jsfiddle, the link is undefined if I lowercase Stack overflow. The 'gi' flag should make the regexp case-insensitive. I wonder what's going on. http://jsfiddle.net/ZRQW7/1/ – Heitor Chang Apr 25 '12 at 17:10
  • @HeitorChang: Thank you for mentioning that. The reason it doesn't work is that the keys in `substitutions` are case-sensitive, even though the regular expression isn't. I've fixed the examples (and added a live example). – T.J. Crowder Apr 25 '12 at 17:15
1

Yes, use String.replace(regex, replaceString) to do that.

Here is an example:

var text = "You should visit StackOverflow. I found it on Wikipedia.";

var newText=text.replace(/stackoverflow/gi,
                         "<a href='http://www.stackoverflow.com/'>StackOverflow</a>");

The g stands for global, so it will replace all instances, and the i means case-insensitive search.

In case you are replacing common words, like "dictionary" to link to dictionary.com it would be better if you only replaced it if your users added a special tag, for example:

"You should visit StackOverflow. I found it on Wikipedia."

shouldn't be replaced with links unless it was written like this:

"You should visit &StackOverflow. I found it on Wikipedia."

Then your method would just need to add the special symbol.

Also, I would have the data in an array like this:

var linkArray = [ ["StackOverflow", "http://www.stackoverflow.com/", "Description"],
                  ["Wikipedia", "http://wikipedia.org/", "Free encyclopedia"] ];

Then create a loop to find and replace the instances:

function addLinks(textInput) {
    for (var i=0; i<linkArray.length; i++) {
        textInput = addLink(textInput, linkArray[i]);
    }
    return textInput;
}

function addLink(textInput, link) {
    var replaceString = "<a href=\"" + link[1] + "\" title=\""
                      + link[2] + "\">"
                      + link[0] + "</a>";
    return textInput.replace(new RegExp("&"+link[0], "gi"), replaceString);
}
Ozzy
  • 8,244
  • 7
  • 55
  • 95
1

What you want to create a clean and extensible code is create a library of word => link then you can iterate over that and do your replace inside your code.

Here is a fiddle demo doing that http://jsfiddle.net/MjV84/

$(function() {

    var text = $('#foo').text(),
        library = {
            stackoverflow: 'http://stackoverflow.com',
            wikipedia: 'http://wikipedia.com'
        },
        name;

    for (name in library) {
        text = text.replace(new RegExp(name, 'gi'), function(word) {
            return '<a href="' + library[name] + '">'+word+'</a>';
        });  
    };

    $('#foo ').html(text);
});​
GillesC
  • 10,647
  • 3
  • 40
  • 55
  • This works OK but it removes all HTML tags. Also, if there are more div#foos on the page, they're all mixed together. – MrEinStain May 06 '12 at 13:01
0

All the previous answers using the i modifier on the regular expression fail if the target string contains variants of the substitution strings differing by case. This is because the target string substring does not match the substitutions attribute name.

This version solves this by capturing each of the substitution strings and searching the arguments array for the found string.

function substitute (str) { 'use strict';
  var substitutions = {
        "Stack Overflow": "http://stackoverflow.com",
        "Wikipedia":     "http://en.wikipedia.org",
        // ...and so on...
      },
      skeys = Object.keys (substitutions);

  // build regexp which will capture each match separtely
  return str.replace (new RegExp ('(' + skeys.join(")|(") + ')', "gi"), function (m0) {
    // Now scan the arguments array (omitting the last two arugments which
    // are the source string and match index)
    for (var ai, i = arguments.length - 2; --i;) {
      // The index of the argument (less 1) corresponds to the index in skeys of
      // the name in the substitutions  
      if ((ai = arguments[i])) {
        return '<a href="' + substitutions[skeys[i - 1]] + '">' + ai + '</a>';
      }
    }    
    return m0;    
  });
}


var str = "You should visit stack overflow. I found it on Wikipedia."; 

// check in console log that links are correctly built.
console.log (substitute (str));
document.write (substitute (str));

See the jsfiddle : http://jsfiddle.net/NmGGN/

HBP
  • 15,685
  • 6
  • 28
  • 34