Jon
Jon

Reputation: 8531

Search String with Regex, and Replace Contents with Data

I have a string that includes values that I would like to have replaced from a JSON object. I have designated these values with {{*}} (ie - {{bird.foot}}). I have written some JavaScript, but am having trouble with:

  1. Selecting only items inside each {{}}. I am selecting everything from the first set of brackets in the string to the last set of bracket in the string.
  2. Replace each item inside the bracket with its corresponding value in the data variable

var data = {
        bird: {
            foot: 'claw',
            mouth: 'beak',
            skin: 'feathers'
        },
        dog: {
            foot: 'paw',
            mouth:'muzzle',
            skin: 'fir'
        }
    },
    html = 'A bird\'s mouth is called a {{bird.mouth}}. A dog has {{dog.skin}} where-as a bird has {{bird.skin}}.',
    regex = /({{)(.)*(}})/igm,
    results = html.match(regex);

console.log(results);

Running the above snippet outputs the array with one element: ["{{bird.mouth}}. A dog has {{dog.skin}} where-as a bird has {{bird.skin}}"]. I was expecting an array with the three elements: [{{bird.mouth}}, {{dog.skin}}, {{bird.skin}}].

Ultimately, I would like results to output: A bird\'s mouth is called a break. A dog has fur where-as a bird has feathers..

Notes:

  1. The properties will not be in an alphabetical order
  2. I am unable to use a Template library for my project. My project involves injecting code onto a page via Optimizely (AB Testing platform). I have access to only writing my own JavaScript.

Upvotes: 0

Views: 68

Answers (2)

Thinh Nguyen
Thinh Nguyen

Reputation: 392

An object when passed to a function can get its property accessed via 'object["property"]'. I also adjusted your regex to '/{{([^{}]*)}}/igm' or else it with count this as one match '{{bird.mouth ... bird.skin}}'.

var data = {
  bird: {
    foot: 'claw',
    mouth: 'beak',
    skin: 'feathers'
  },
  dog: {
    foot: 'paw',
    mouth: 'muzzle',
    skin: 'fur'
  }
};
var html = 'A bird\'s mouth is called a {{bird.mouth}}. A dog has {{dog.skin}} where-as a bird has {{bird.skin}}.';


function getProperty(object, propertyNames) {
  var regex2 = /([^\.]+)/g;
  var results2 = regex2.exec(propertyNames);
  var ret = object;
  while (results2 != null) {
    var temp = results2[1];
    ret = ret[temp];

    results2 = regex2.exec(propertyNames);
  }

  return ret;
};

function replace(data, html) {
  var html2 = html;
  var regex = /{{([^{}]*)}}/igm;

  var results = regex.exec(html);
  while (results != null) {
    var temp0 = results[0];
    var temp1 = results[1];
    html2 = html2.replace(temp0, getProperty(data, temp1));
    results = regex.exec(html);
  }

  return html2;
}


var str = replace(data, html);
console.log(str);
document.write(str);

Upvotes: 0

Amadan
Amadan

Reputation: 198436

var data = {
        bird: {
            foot: 'claw',
            mouth: 'beak',
            skin: 'feathers'
        },
        dog: {
            foot: 'paw',
            mouth:'muzzle',
            skin: 'fir'
        }
    },
    html = 'A bird\'s mouth is called a {{bird.mouth}}. A dog has {{dog.skin}} where-as a bird has {{bird.skin}}.',
    regex = /{{([^]*?)}}/g,
    results = html.match(regex);


// clean way, only for prop.prop.prop
var result = html.replace(regex, function(_, e) {
  var down = e.split(/\./);
  var datum = data;
  while (down.length) {
    datum = datum[down.shift()];
  }
  return datum;
});
console.log(result);

//evil way, more flexible, less safe, slower
var result = html.replace(regex, function(_, e) {
  return eval("data." + e);
});
console.log(result);
<!-- results pane console output; see http://meta.stackexchange.com/a/242491 -->
<script src="http://gh-canon.github.io/stack-snippet-console/console.min.js"></script>

Upvotes: 1

Related Questions