Oscar Godson
Oscar Godson

Reputation: 32776

In JavaScript how do I get all matches using regex instead of the last one

I'm struggling to figure out how to get this regex to work without needing a loop. Here's the code that works:

var template = {name: "Oscar", anotherName: "your twin", hello: 'world'}
var str = "Hello, {{name}} I'm {{anotherName}}. Hello to the {{hello}}"

Object.keys(template).forEach(function (keyName) {
    pattern = new RegExp('{{' + keyName + '}}', 'g');
    str = str.replace(pattern, template[keyName]);
})

// => str "Hello, Oscar I'm your twin. Hello to the world"

The thing about this code I don't like is that it's in a loop generating regex when I feel like a regex should be able to handle this use case. However, my regex is always only matching the last item. I was doing regex like str.match(/({{.}})/gi) but then only the {{hello}} was getting matched.

Preferably I'd like to do something where I can get all matches in an array and then map the array like matchesFromRegex.map(match => template[match]).join('')

Also, I'm in an vanilla JS environment so .matchAll (which isn't supported in IE) wouldn't work.

Upvotes: 0

Views: 25

Answers (1)

Jacob
Jacob

Reputation: 78920

In a RegExp string, { has a special meaning (it lets you set a cardinality for a match, like \d{5} for five digits).

Use new RegExp('\\{\\{' + keyName + '}}', 'g'); instead. The double backslash in JavaScript will create a backslash, which will escape the { character.

If you want to avoid the loop, you can use the function-based version of replace instead:

const pattern = /\{\{([^}]*)}}/g;
str.replace(pattern, (_, key) => template[key]);

To break it down, pattern has a capture group (the parts in ()). The String.prototype.replace function can let you supply a function for doing replacements, which will be passed your match results.

Upvotes: 2

Related Questions