Alex Alex - 5 months ago 11
Javascript Question

How to replace from regex with random value at each occurrence?

I have this kind of sentences:

var str = 'The <adjective> <noun> and <noun> <title>';


I would like to replace each
<pattern>
by a random value from their related array.

In my previous example I'd like to get something similar to:

var adjectives = ['big' 'small' 'funny'];
var nouns = ['dog', 'horse', 'ship'];
var title = ['bar', 'pub', 'club'];

var str = 'The <adjective> <noun> and <noun> <title>';
var r = str.replacePatterns({ noun: nouns, adjective: adjectives, title: titles });
console.log(r); // The big horse and ship club


I almost get it by didn't tough about same pattern (e. g.
<noun>
) twice in the same sentence. So I generate only one random value for each pattern...

String.prototype.replacePatterns = function (hash) {

var string = this,
key;

for (key in hash) {
if (hash.hasOwnProperty(key)) {
var randomValue = hash[key][Math.floor(Math.random() * hash[key].length)];
string = string.replace(new RegExp('\\<' + key + '\\>', 'gm'), randomValue);
}
}

return string;
};


Could you help me to get something replacing each pattern by a random value instead of a global replacement?

I don't know how to loop result of a regex to replace the matches in the original sentence (with random value each time).

Answer

replace accepts a function as its second argument, which is called for each replacement and can return the value to replace with. So use a function and move the random number generation into it:

String.prototype.replacePatterns = function (hash) {

    var string = this,
        key,
        entry;

    for (key in hash) {
        if (hash.hasOwnProperty(key)) {
            entry = hash[key]
            string = string.replace(new RegExp('\\<' + key + '\\>', 'gm'), function() {
                return entry[Math.floor(Math.random() * entry.length)]
            });
        }
    }

    return string;
};

You don't need it here, but just FYI, the function receives the matched text as its first argument, and if you have capture groups in your regular expression (you don't), it receives them as subsequent arguments. Details in the MDN page for String#replace or, of course, the spec.