'Replace multiple placeholders with their corresponding values in string
I have a command to make a custom welcome message so when someone say changes the title to the custom placeholder {user.id} it would change the title to the joining users ID
I tried ${(cardText, placeholders)} but that just returns [object Object] in the embed
So cardText is {user.tag} so i want it to look in placeholders and see if there is a placeholder in the string and if there is change it to the right value so in this case it would change it to member.user.tag
Code:
module.exports = async (client, member) => {
const guildSchema = require('../../models/guildSchema');
const data = await guildSchema.findOne({
id: member.guild.id
});
const placeholders = {
'{client.avatar}': client.user.displayAvatarURL(),
'{client.username}': client.user.username,
'{client.mention}': client.user,
'{client.tag}': client.user.tag,
'{client.id}': client.user.id,
'{user.avatar}': member.user.displayAvatarURL(),
'{user.username}': member.user.username,
'{user.mention}': member.user,
'{user.tag}': member.user.tag,
'{user.id}': member.user.id,
'{guild.memberCount}': member.guild.memberCount,
'{guild.icon}': member.guild.iconURL,
'{guild.name}': member.guild.name,
'{guild.id}': member.guild.id,
};
const cardTitle = (data.welcome.title === null) ? 'Welcome To The Server' : data.welcome.title;
const cardText = (data.welcome.text === null) ? '{user.tag}' : data.welcome.text;
const cardSubtitle = (data.welcome.subtitle === null) ? 'Member Count: {guild.memberCount}' : data.welcome.text;
const embed = new Discord.MessageEmbed()
.setTitle(`${(cardTitle, placeholders)}`),
.setDescription(`${(cardText, placeholders)}`),
.setFooter(`${(cardSubtitle, placeholders)}`),
channel.send({ embeds: [embed] });
}
Solution 1:[1]
Let's use regular expressions to do the matching for us. Because your keys have characters that have special meaning in regular expressions ({ and }), we'll need to escape those.
Pulled from escape-string-regexp:
const escapeRegex = (string) => string
.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&')
.replace(/-/g, '\\x2d');
Then let's write a function that takes a template and the placeholders. We should create a regular expression from the placeholder like this:
const regex = new RegExp("(" + Object.keys(placeholders).map(escapeRegex).join("|") + ")", "g");
For each key in the placeholders object, we escape the special characters, and join it all with |, wrapping the result in parentheses. Then we give it the g (global) flag so it provides us all the matches.
For you, this generated regex would look something like:
/(\{client.avatar\}|\{client.username\}|...|\{guild.id\})/g
Lastly, we want to use this regex and replace all occurrences of placeholders with their corresponding value.
return template.replace(regex, (_, match) => placeholders[match]);
So the full code looks like this:
const escapeRegex = (string) => string
.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&')
.replace(/-/g, '\\x2d');
function fill(template, placeholders) {
const regex = new RegExp("(" + Object.keys(placeholders).map(escapeRegex).join("|") + ")", "g");
return template.replace(regex, (_, match) => placeholders[match]);
}
Example usage:
fill("My name is {name}!", { "{name}": "Kelly" }); // "My name is Kelly!"
You can try it out here, just click the link and hit "Run". To the right you'll see the output.
Why don't we just use something like this:
template
.replaceAll("{client.avatar}", placeholders["{client.avatar}"])
.replaceAll("{client.username}", placeholders["{client.username}"])
.replaceAll(...)
// ...
Well first of all, that's not really DRY, is it? You could help with that using a loop:
for (const [place, value] of Object.entries(placeholders)) {
template = template.replaceAll(place, value);
}
But then there's a catch! What if some placeholder's value contained another placeholder? Then you'd replace the new placeholder with a new value! This might lead to unexpected behavior, which is why I suggested using this solution instead; replace all matches at once, preventing this from happening.
Placeholders:
{bar} => i love {foo}
{foo} => 42
And then:
say {bar}
say i love {foo}
say i love 42
Uh oh!
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | hittingonme |
