How can I replace all matches of a string? - javascript

I am trying to replace some sort of self made variables from multiple strings in an array.
Later I will make a promp for the user to ask for the replacement, but in the first step I'm just trying to replace it with a 'test' value ('###').
Oh and I want it to be simplified (with the chained functions - I've only just discovered for myself and thats the problem here :D ). Can someone please help me?
What I got so far:
const replaceAll = (obj) => {
obj.cmds.forEach((element, index, array) => {
obj.cmds[index] = obj.cmds[index].match(/{.*?}/gmi).map((value) => {
console.log('valuex', value)
/*
// Here the user should be asked for the replacement in the future.
// const newValue = userPromp(value)
*/
return obj.cmds[index].split(value).join('###')
})
})
return obj
}
const newObj = replaceAll({
name: 'ULTRA TEST',
cmds: [
'port {port}',
'port {port} und random {random}',
'random {random} und value {value}'
]
})
console.log(newObj)

I think what you are looking for is something like this:
You can see that instead of using match, i just use Replace and pass in the regex.
replaceAll = (obj) => {
var m = {};
obj.cmds.forEach((element, index, array) => {
obj.cmds[index].match(/{.*?}/gmi).map( value => {
var r = m[value]
if (!r) { /* Create Prompt here. */ r = Math.random() * 10 }
m[value] = r;
})
Object.keys(m).map( key => {
obj.cmds[index] = obj.cmds[index].replace(key, m[key])
});
})
return obj
}
newObj = replaceAll({
name: 'ULTRA TEST',
cmds: [
'port {port}',
'port {port} und random {random}',
'random {random} und value {value}'
]
})
The json which is returned by newObj is:
{
"name":"ULTRA TEST",
"cmds":[
"port 1",
"port 1 und random 2",
"random 2 und value 3"
]
}
So what will happen is that it will only prompt the user for values not previously prompted for in that iteration of replaceAll.
This will do exactly what you want.

i guess you need something like this
const replaceAll = obj => ({
...obj,
cmds: obj.cmds.map(string => {
let result = string;
string.match(/{.*?}/gmi).forEach(template => {
// build <replace-string> here
result = result.split(template).join('$$$');
});
return result;
})
});
const newObj = replaceAll({
name: 'ULTRA TEST',
cmds: [
'port {port}',
'port {port} und random {random}',
'random {random} und value {value}'
]
})
console.log(newObj)

You can use the inbuilt replace function.
String.replace(/regex here/, <string to replace the matched regex>)
So for your case, I could do:
// take input here
let input = <input from user>
// string to replace with
let replacementString = "###"
for (let cmd of cmds) {
cmd.replace(/`${input}`/gmi, replacementString);
}
Use for of instead of forEach as you cannot execute break in the latter. (Assuming you might want to have functionality of replacing one by one in the future).

Related

Global Tag replace in text from a objet/array (Tag -> value) javascript

I am using a piece of code to replace "Tags" by values in Strings
My concern is that it only changes the first Tag encountered if it exists several times :(
const replaceTagsToValue = (obj, chaine) => obj.reduce((f, s) => `${f}`.replace(Object.keys(s)[0], s[Object.keys(s)[0]]), chaine)
const Tags = [
{ "{info_1}": "One" },
{ "{info_2}": "Two" },
{ "{info_3}": "Three" }
// etc etc...
]
let input = "{info_1}-{info_2}-{info_3} | {info_3}-{info_2}-{info_1}";
let output = replaceTagsToValue(Tags, input);
console.log(output);
Result:
One-Two-Three | {info_3}-{info_2}-{info_1}
Want these result:
One-Two-Three | Three-Two-One
I tested with the addition of a global regex approach, without success of course:
.replace(/Object.keys(s)[0]/g, s[Object.keys(s)[0]])
Do you have a solution ? see a more suitable and more generic or best practice solution?
Thank's !
In this case you cannot use the literal notation (/Object.keys(s)[0]/g) to build a dynamic RegExp,
you need to use the constructor (new RegExp(Object.keys(s)[0], 'g')) instead:
const replaceTagsToValue = (obj, inStr) => obj.reduce((f, s) => f.replace(new RegExp(Object.keys(s)[0], 'g'), s[Object.keys(s)[0]]), inStr)
const Tags = [
{ '{info_1}': 'One' },
{ '{info_2}': 'Two' },
{ '{info_3}': 'Three' }
// etc etc...
]
const input = '{info_1}-{info_2}-{info_3} | {info_3}-{info_2}-{info_1}'
const output = replaceTagsToValue(Tags, input)
console.log(output)

Return keys that have value with the given phrase (array)

I have problem with JavaScript array. I am trying to create a function that, according to a particular arg, returns keys with a value that has that arg.
The code I tried:
for(let i in client.commands.size) {
let filteredCommands = client.commands.filter(cmd => cmd[i].help.cmdCategory = arg).map(c => c.name)
console.log(filteredCommands)
embed.addField(`${filteredCommands.help.name}`, `**Description:** ${filteredCommands.help.desc}\n**Usage:** \`${client.prefix}${filteredCommands.help.usage}\`\n**Exxample Usage:** ${filteredCommands.help.exampleUsage}`, false)
}
client.commands it's a array who key is name of command, and value in command key (example. ping) named cmdCategory is in help subkey and need value same in argument and next return keys which meet this condition. (for example: if key value cmdCategory have value fun, then return keys who meet this criteria. Any ideas for here? Thanks anyway.
If your object client looks like this example then you can try it
let arg = 'sh'
let client = {
commands: [
[
{
help: {
cmdCategory: 'bash',
name: 'some bash name',
desc: 'description for bash'
}
},
{
help: {
cmdCategory: 'sh',
name: 'some sh name',
desc: 'description for sh'
}
}
]
]
}
// reduce from [[{}, {}]] to [{},{}]
let commands = client.commands.reduce((prev, next) => {
return prev.concat(next)
})
let filteredCommands = commands.filter(command => command.help.cmdCategory === arg)
console.log(filteredCommands)
filteredCommands.forEach(cmd => {
/* embed.addField(`${cmd.help.name}`, `**Description:** ${cmd.help.desc}\n**Usage:** \`${client.prefix}${cmd.help.usage}\`\n**Exxample Usage:** ${cmd.help.exampleUsage}`, false) */
})
// OR you can do this:
filteredCommands = []
client.commands.forEach(cmd => {
cmd.forEach(item => {
if (item.help.cmdCategory === arg) {
filteredCommands.push(item)
}
})
})
console.log(filteredCommands)

Accessing JSON by using a constant

My JSON looks as following:
{
flight_number: 1,
mission_name: "FalconSat",
rocket: {
rocket_id: "falcon1",
rocket_name: "Falcon 1",
rocket_type: "Merlin A",
first_stage: {
cores: [
{
core_serial: "Merlin1A",
flight: 1
}
]
},
fairings: {
reused: false,
recovery_attempt: false,
recovered: false,
ship: null
}
},
links: {
video_link: "https://www.youtube.com/watch?v=0a_00nJ_Y88",
flickr_images: [ ]
},
details: "Engine failure at 33 seconds and loss of vehicle"
}
To access the video link, I want to use a constant and I've been trying to use:
const links = "links";
const video1 = links + ".video_link"; // this doesn't work
const video2 = "links.video_link"; // this doesn't work
const det = "details";
getVideoURL(something) {
console.log(something.video1); // undefined
console.log(something.links.video_link); // this works
console.log(something.det); // this works
return something.video2;
}
getDetails(something) {
return something.det; // this works
}
// the jsonObject is retrieved by an async function, i just simplified it. I hope this makes sense.
const jsonObject = await axios("https://api.spacexdata.com/v3/launches");
let url = getVideoURL(jsonObject);
let det = getDetails(something);
console.log(url) // undefined
console.log(det) // prints out details.
Is there a way I can get the video URL like how I've done it with getDetails by using return something.video1 or return something.video2?
Use an array instead of a string, and then you can use reduce to iterate over each key in the array, accessing the appropriate nested property value, passing in the entire object as the initial value of the accumulator a:
const obj = {flight_number:1,mission_name:"FalconSat",rocket:{rocket_id:"falcon1",rocket_name:"Falcon 1",rocket_type:"Merlin A",first_stage:{cores:[{core_serial:"Merlin1A",flight:1}]},fairings:{reused:!1,recovery_attempt:!1,recovered:!1,ship:null}},links:{video_link:"https://www.youtube.com/watch?v=0a_00nJ_Y88",flickr_images:[]},details:"Engine failure at 33 seconds and loss of vehicle"};
const getVideoURL = obj => path.reduce((a, prop) => a[prop], obj);
const path = ['links', 'video_link'];
const url = getVideoURL(obj);
console.log(url);
Alternatively, if you wanted to use a string, you would have to split on .s first:
const pathString = "links.video_link";
const getVideoURL = obj => pathString
.split('.')
.reduce((a, prop) => a[prop], obj);

Want to return true or false when finding an exact match in an array of objects?

I have a posList that contains an array of objects. I want to check if the entered value is an exact match of all the posCode in each object of the posList. My RegExp returns true when its a search match. For example, when 4325
is entered it returns true. I only want it to return true if the match is exact.
//short example
posList = [
{
posCode: "43252",
description: "hi"
},
{
posCode: "HTD632",
description: "hello"
}
]
checkPosCodeUnique = () => {
const re = new RegExp(_.escapeRegExp(this.state.posCode), 'i');
const isMatch = result => (re.test(result.posCode));
const list = _.filter(this.state.posList, isMatch);
if (list.length > 0) {
error=true;
}
};
Why do you need to use regex?
posList = [{
posCode: "43252",
description: "hi"
},
{
posCode: "HTD632",
description: "hello"
}
]
checkPosCodeUnique = (search) => {
return posList.some(item => { return item.posCode == search });
};
console.log(checkPosCodeUnique('43252'));
console.log(checkPosCodeUnique('HTD632'));
console.log(checkPosCodeUnique(123));
Use some method of arrays:
console.log(posList.some(pos => pos.posCode.toUpperCase() === this.state.posCode.toUpperCase());
For what you describe, you don't need regular expressions, you can simply filter the list:
posList.filter(e => e.posCode === posCode)
See https://codesandbox.io/s/5w95r4zmvl for an implementation of your version and the one using a simple filter.

Call nested methods on object only if it exists using Ramda

I currently have a user object, which has a currentRoom() method on it, which might sometimes not exist or return null.
If the currentRoom() method returns something, I then need to call a messages() method on that. If nothing is returned from either, I’d like to return a default empty array [].
I’d like to tackle this functionally using Ramda, so it’s neat and reusable. Currently, my (non Ramda) code looks like this:
const user = Users.findOne({ username: params.id })
const room = (user.currentRoom && user.currentRoom() || {})
const messages = (room.messages && room.messages() || [])
Some kind of logic I was thinking was to pass in the list of required methods, along with the default result if nothing comes out of it.
/* getMessages(defaultIfNull, methodsArray, object) */
getMessages([], ['currentRoom', 'messages'], user)
Basically something a bit similar to pathOr, but for methods on objects.
I guess I'd use the List monad like an Option:
const getRoom = user => "currentRoom" in user ? [user.currentRoom()] : [];
const getMessages = room => "messages" in room ? room.messages() : [];
const allTogether = R.compose(R.chain(getMessage), R.chain(getRoom), R.of);
console.log(allTogether(Users.findOne({ username: params.id })));
You can use a point-free solution using just Ramda. First, we define a withDefaults function which will set up currentRoom and messages methods in objects which these methods are undefined.
var withDefaults = R.pipe(
// if don't have `currentRom` add a
// `currentRom` function that returns an empty object
R.unless(
R.hasIn('currentRoom'),
R.assoc('currentRoom',
R.always({}))),
// if don't have `messages` add a
// `messages` function that returns an empty array
R.unless(
R.hasIn('messages'),
R.assoc('messages',
R.always([]))))
This function filters the object setting up methods if needed. Usage example.
var user = withDefaults(getById(id))
Next, define a getter functions to get rooms and messages from objects. invoker is the central piece of this snipet, it returns a function that invokes a method. See http://ramdajs.com/docs/#invoker
var getCurrentRoom = R.invoker(0, 'currentRoom')
var getMessages = R.invoker(0, 'messages')
Above code can be used as following.
var userWithRoom = withDefaults({
currentRoom : function () {
return {
number : '123'
}
}
})
var userWithMessages = withDefaults({
messages : function () {
return [
'get lunch'
]
}
})
var userWithAll = withDefaults({
currentRoom : function () {
return {
number : '123'
}
},
messages : function () {
return [
'get lunch'
]
}
})
var userWithNone = withDefaults({})
All together
var withDefaults = R.pipe(
R.unless(
R.hasIn('currentRoom'),
R.assoc('currentRoom',
R.always({}))),
R.unless(
R.hasIn('messages'),
R.assoc('messages',
R.always([]))))
var getCurrentRoom = R.invoker(0, 'currentRoom')
var getMessages = R.invoker(0, 'messages')
// examples
var userWithRoom = withDefaults({
currentRoom : function () {
return {
number : '123'
}
}
})
var userWithMessages = withDefaults({
messages : function () {
return [
'get lunch'
]
}
})
var userWithAll = withDefaults({
currentRoom : function () {
return {
number : '123'
}
},
messages : function () {
return [
'get lunch'
]
}
})
Now lets test above code using console.log to see if our solution works as expected
console.log(getCurrentRoom(userWithRoom))
console.log(getCurrentRoom(userWithMessages))
console.log(getCurrentRoom(userWithAll))
console.log(getCurrentRoom(userWithNone))
console.log('---')
console.log(getMessages(userWithRoom))
console.log(getMessages(userWithMessages))
console.log(getMessages(userWithAll))
console.log(getMessages(userWithNone))
The output should be:
{ number: '123' }
{}
{ number: '123' }
{}
---
[]
[ 'get lunch' ]
[ 'get lunch' ]
[]

Categories

Resources