-2

I have to address an algo problem with vanilla JS. I have a string:

let stringExample = "my {cat} has {2} ears";

And I want to replace it (in order) with an array of replacements

const replaceArray = ["dog", "4"];

So that after the replacement, the stringExample should be:

"my dog has 4 ears"
XWRan
  • 1
  • 1
  • 2
    When you attempted to write the solution to your problem, what code did you come up with? What went wrong? What have you tried to do? Do you have any errors? What's your "*[mcve]*" code? I'd suggest taking the [tour] and also reading the "*[ask]*" guidance. – David Thomas Mar 24 '21 at 20:09
  • This is really close to [Handlebars](https://handlebarsjs.com). Would that work better? It exists and is tested. – tadman Mar 24 '21 at 20:10
  • @tadman its not a handlebars project, so external tools are not allowed, I suppose this issue can be adressed by JS language alone? – XWRan Mar 24 '21 at 20:12
  • 2
    Yeah, it *can*, but it's not as easy. It'd be great if you stated your requirements *up front* so we don't have to guess what you can and can't use. There are numerous JavaScript template systems which are all, amazingly, open-source so you can probably find the parts you want and repurpose those, license permitting. – tadman Mar 24 '21 at 20:12
  • Hint: `replace(/.../g, m => { ... })` The `replace()` function can take a function for the *replacer* which gives you considerable flexibility here. – tadman Mar 24 '21 at 20:15
  • @tadman havent tried that before, could be doable. I'll try and poste my solution here if I found one :) – XWRan Mar 24 '21 at 20:18
  • Use this: `'my {speical-cat} has {two-hundred} ears'.replace(/{([^}]+)}/g, (_,a)=>'{'+[...a].sort((t)=>0.5-Math.random()).join\`\`+'}')`. It will randomize what is inside the brackets. You can adjust it how you like. – quicVO Mar 24 '21 at 20:18
  • @quicVO Some kind of Madlib generator? – tadman Mar 24 '21 at 20:19
  • @tadman, no it will give a random outcome like `my {tials-capec} has {nhoeduwtr-d} ears` or `my {spl-atiecca} has {-ndrwdouteh} ears` from `my {speical-cat} has {two-hundred} ears` – quicVO Mar 24 '21 at 20:21
  • Something like this should work: `const replaceBrackets = (str, replacements) => str .replace (/\{([^}]*)\}/g, ((i) => (_, s) => replacements[i++] || s)(0))` – Scott Sauyet Mar 24 '21 at 20:29
  • Voted to reopen as the suggested duplicate wanted to replace only numeric bracket-surrounded keys, and not arbitrary ones like `{cat}`. – Scott Sauyet Mar 24 '21 at 20:35

1 Answers1

0

One approach that can be used is as follows:

// a sample of Strings and their corresponding replacement-arrays:
let string1 = "my {cat} has {2} ears",
  arr1 = ["dog", "4"],
  string2 = "They call me ~Ishmael~",
  arr2 = ['Susan'],
  string3 = "It is a #@truth@# #@universally acknowledged@#...",
  arr3 = ['questionable assertion', 'oft cited'];

// here we use a named Arrow function which takes three arguments:
// haystack: String, the string which features the words/characters to
// be replaced,
// needles: Array of Strings with which to replace the identified
// groups in the 'haystack',
// Array of Strings, these strings represent the characters with
// which the words/characters to be replaced may be identified;
// the first String (index 0) is the character marking the begining
// of the capture group, and the second (index 1) indicates the
// end of the captured group; this is supplied with the default
// curly-braces:
const replaceWords = (haystack, needles, delimiterPair = ['{', '}']) => {
  // we use destructuring assignment, to assign the string at
  // index 0 to the 'start' variable, the string at index 1 to
  // the 'end' variable; if no argument is provided the default
  // curly-braces are used/assigned:
  const [start, end] = delimiterPair,
  
  // here we construct a regular expression, using a template
  // string which interpolates the variables within the string;
  // the regular expression is composed of:
  // 'start' (eg: '{')
  // .+ : any character that appears one or more times,
  // ? : lazy quantifier so the expression matches the
  // shortest possible string,
  // 'end' (eg: '}'),
  // matched with the 'g' (global) flag to replace all
  // matches within the supplied string.
  // this gives a regular expression of: /{.+?}/g
  regexp = new RegExp(`${start}.+?${end}`, 'g')
  
  // here we compose a String using the template literal, to
  // interpolate the 'haystack' variable and also a tab-character
  // concatenated with the result returned by String.prototype.replace()
  // we use an anonymous function to supply the replacement-string:
  // 
  return `"${haystack}":\t` + haystack.replace(regexp, () => {
    // here we remove the first element from the array of replacements
    // provided to the function, and return that to the string as the
    // replacement:
    return needles.shift();
  })
}

console.log(replaceWords(string1, arr1));
console.log(replaceWords(string2, arr2, ['~', '~']));
console.log(replaceWords(string3, arr3, ['#@', '@#']));

JS Fiddle demo.

This has no sanity checks at all, nor have I explored to find any edge-cases. If at all possible I would seriously recommend using an open source – and well-tested, well-proofed – framework or templating library.

References:

Bibliography:

David Thomas
  • 249,100
  • 51
  • 377
  • 410