How can I pass variable to replace function?
function fname(object, object2){
object.text.replace(/{{[^}}]+}/g,function(m,key){
return object.replaceText[object2[m.substring(2, m.length-2)]];
});
}
objects are similar:
object = {
text : 'some text where I want replace {{some}} string',
replaceText : {
'1' : 'newText'
}
}
object2 = {
some : 1
}
Thanks for help.
EDIT:
I find another way to do this, here is no problem with variable scope:
function fname(object1, object2){
var reg = new RegExp(/{{[^}}]+}}/g);
var result;
while((result = reg.exec(object1.text)) !== null) {
object1.text = object1.text.replace(result[0],object1.replaceText[object2[result[0].substring(2, result[0].length-2)]]);
}
}
Thanks for everyone!
String.prototype.replace returns new string, so change your function like this:
function fname(object1, object2) {
object1.text = object1.text.replace(/{{([^}}]+)}}/g,function(m,key){
return object1.replaceText[object2[key]];
});
}
Also change regexp to /{{([^}}]+)}}/g (note parenthesis). ([^}}]+) is a matching group so you can populate key variable and avoid substring inconvenience.
Related
So I've been trying to find a solution to this for a little while with no luck.
const nameTest = 'testName';
const test = {
RANDOM_ONE: {
NAME: 'testName',
SOMETHING: {...}
},
RANDOM_TWO: {
NAME: 'Name',
SOMETHING: {...}
}
}
Is there any simple, easy way where I can compare the nameTest and the NAME key without knowing what the RANDOM_X is in order to access NAME?
You can use Object.keys() to get the array of all the keys. Then loop through the array to check the property:
const nameTest = 'testName';
const test = {
RANDOM_ONE: {
NAME: 'testName',
SOMETHING: {}
},
RANDOM_TWO: {
NAME: 'Name',
SOMETHING: {}
}
}
let testKeys = Object.keys(test);
testKeys.forEach(function(k){
console.log(test[k].NAME == nameTest);
});
You can use a for ... in loop:
for (let key in test) {
if (test[key].NAME === nameTest) {
// do something
}
}
I hope we know that 2 levels down into test is your object. You could write a function, to compare the name key.
function compare(obj, text){
for(let x in obj){
if(obj.x.name == text) return true;
else ;
}
}
Then call the function with your object and the string.
let a = compare(test, nameTest);
Note: this would compare the object to only ascertain if it contains the nameTest string.
var obj= test.filter(el){
if(el.NAME==nameTest)
{
return el;
}
}
var x= obj!=null?true:false;
You could use find.
The find method executes the callback function once for each index of
the array until it finds one where callback returns a true value. If
such an element is found, find immediately returns the value of that
element. Otherwise, find returns undefined.
So it is more memory efficient, than looping over the whole object with forEach, because find returns immediately if the callback function finds the value. Breaking the loop of forEach is impossible. In the documentation:
There is no way to stop or break a forEach() loop other than by
throwing an exception. If you need such behavior, the forEach() method
is the wrong tool.
1. If you want to get the whole object
var nameTest = 'testName';
var test = {
RANDOM_ONE: {
NAME: 'testName',
SOMETHING: {}
},
RANDOM_TWO: {
NAME: 'Name',
SOMETHING: {}
}
};
function getObjectByNameProperty(object, property) {
var objectKey = Object.keys(object)
.find(key => object[key].NAME === property);
return object[objectKey];
}
var object = getObjectByNameProperty(test, nameTest);
console.log(object);
2. If you just want to test if the object has the given name value
var nameTest = 'testName';
var test = {
RANDOM_ONE: {
NAME: 'testName',
SOMETHING: {}
},
RANDOM_TWO: {
NAME: 'Name',
SOMETHING: {}
}
};
function doesObjectHaveGivenName(object, nameValue) {
var objectKey = Object.keys(object)
.find(key => object[key].NAME === nameValue);
return objectKey ? true : false;
}
console.log( doesObjectHaveGivenName(test, nameTest) );
I want to substitute variables in a string like console.log does.
What I want to achieve is something like this:
let str = 'My %s is %s.';
replaceStr(string, /* args */) {
// I need help with defining this function
};
let newStr = replaceStr(str, 'name', 'Jackie');
console.log(newStr);
// output => My name is Jackie.
/*
This is similar to how console.log does:
// console.log('I\'m %s.', 'Jack');
// => I'm Jack.
*/
I am not able to figure out how to do that. Any help will be much appreciated.
Thank you.
You could prototype it to the String object. Something like this:
String.prototype.sprintf = function() {
var counter = 0;
var args = arguments;
return this.replace(/%s/g, function() {
return args[counter++];
});
};
let str = 'My %s is %s.';
str = str.sprintf('name', 'Alex');
console.log(str); // 'My name is Alex'
You can use spread operator (ES6):
function replaceStr(string, ...placeholders) {
while (placeholders.length > 0) {
string = string.replace('%s', placeholders.shift());
}
return string;
}
EDIT: Based on lexith's answer, we can avoid the explicit loop:
function replaceStr(string, ...placeholders) {
var count = 0;
return string.replace(/%s/g, () => placeholders[count++]);
}
If hope you want to have custom logger function.
console.log can replace %s, with below approach your custom function gets full feature set of console.log and its more efficient.
function myLogger() {
if(logEnabled) {
// you can play with arguments for any customisation's
// arguments[0] is first string
// prepend date in log arguments[0] = (new Date().toString()) + arguments[0] ;
console.log.apply(console, arguments);
}
}
function replaceStr(string, ...placeholders) {
const replaced = string.replace(/%s/g, () => placeholders.shift());
return [replaced, ...placeholders].join(' ');
}
This will append any remaining placeholders to the string to more accurately replicate console.log.
I have an object:
var obj= {
hello:{
it:"ciao",
en:"hello"
}
}
Now the problem is that i can't access a value through obj.hello[lang], neither obj.hello.en.
i have a string like 'hello.it' or 'hello.en' and I want to get something like obj[myString] that became obj.hello.en
I tried to split the string with .split('.'), but i have to loop hard coded through the length result
How can i achieve this?
I don't understand... obj.hello.it should work
var obj= {
hello:{
it:"ciao",
en:"hello"
}
}
console.log(obj.hello.it);
If you need to get this value from a string 'hello.it' I would do something like that :
var obj= {
hello:{
it:"ciao",
en:"hello"
}
}
var helloIt = 'hello.it';
var helloEn = 'hello.en';
function translate(s){
var values = s.split('.');
var resource = values[0];
var lang = values[1];
return obj[resource][lang];
}
console.log(translate(helloIt));
console.log(translate(helloEn));
After that you have to manage some cases (if the string has not the right format, if the translation does not exist...). You could manage that everything in a translation module or something... Hope it helps ;)
EDIT :
If you want to have a way to 'explore' objects using a string you can do something like that :
var obj= {
hello:{
it:"ciao",
en:"hello"
}
};
function explore(o, s){
return s.split('.').reduce(function(r, ss){
return r && r[ss] ? r[ss] : null;
}, o);
}
console.log(explore(obj, 'hello.it'))
Hi if your string is something like 'hello.it' you can do this hope it helps
var obj= {
hello:{
it:"ciao",
en:"hello"
}
};
var str = 'hello.it';
alert(obj[t.split('.')[0]][t.split('.')[1]]);
You could split the path and iterate it and reduce the object you have. This proposal works with a default value for missing properties.
var obj= { hello: { it: "ciao", en: "hello" } },
path ='hello.it',
value = path.split('.').reduce(function (o, k) {
return (o || {})[k];
}, obj);
console.log(value);
Try this, it will work for whichever level you want.
var obj= {
hello:{
it:"ciao",
en:"hello"
}
}
var lang='hello.it';
var val=obj;
lang.split('.').forEach(function(c){val=val[c]});
console.log(val);//Should output ciao
Personaly, I don't know why you don't use eval.
var str = "hello.it";
eval("obj." + str);
I thin eval is best if str is hardcoded.
And I think you can refer this.
Here's a sample showing how you can walk down an object:
var obj= {
hello:{
it:"ciao",
en:"hello"
}
}
var path='hello.it'.split('.');
x=obj;
for (var i=0;i<path.length;i++)
{
x=x[path[i]];
console.log(x);
}
Edit To modify the value you can use the same style, but you need to know when your at the string. This really will depend on your requirements and your actual object model but here's an example
for (var i=0;i<path.length;i++)
{
a=x[path[i]];
if(typeof(a)=='string')
{
x[path[i]]='NewString'
console.log(x[path[i]]);
break;
}
x=a
console.log(x);
}
this should work:
var obj= {
hello:{
it: "ciao",
en: "hello"
}
};
var input = "hello.it"; //change this to the value you wish to get.
var str = "obj".concat(".").concat(input);
console.log(eval(str));
The basic idea is to check if it starts with an underscore and if there is split the string and return whatever comes after the underscore. This function will be run many times, but for different strings, it is unlikely i will need to retrieve the information more than once for each stirng.
A simple function which will return an object with the data I need:
var parseElementName = function(i) {
var sliced = [i.slice(0, 1), i.slice(1, i.length)];
var obj = {
isClass: null,
name: ''
}
if(sliced[0] === '_') {
obj.name = sliced[1];
obj.isClass = true;
} else {
obj.name = i;
obj.isClass = false;
}
return obj
}
Called with parseElementName(i);
Object with prototyped function
var parsedElement = function(i) {
this.className =
this.isClass = null;
if(this.setElementName(i))
return true
}
parsedElement.prototype.setElementName = function(i) {
var sliced = [i.slice(0, 1), i.slice(1, i.length)];
if(sliced[0] === '_') {
this.className = sliced[1];
this.isClass = true
} else {
this.className = i;
this.isClass = false
}
}
Called with var parsed_element = new parsedElement();
then parsed_element.className or parsedElement.isClass
Which approach is recommended?
I like the object prototype approach best, but I have a few notes about your code:
Use semicolons at the end of each line
Class names should be capitalized. So it should be ParsedElement
I wouldn't call it className, because it is confusing when it is not a class, I would rename it name
The two ways have different outcomes - that constructor+prototype approach will yield an instance which has a setElementName method. Will you ever need this to change the fields of an existing object? It's a simple parser function, so I would assume no. In that case, you should go with returning the object literal:
function parseElementName(i) {
var isClass = i.charAt(0) == '_';
return {
isClass: isClass,
name = isClass ? i.slice(1) : i
};
}
If you really need that method later, consider #MaxMeier's and #HMR's points.
Let's say I have the following object:
var map = {};
map[/^\/e\/(?:([0-9a-f]{24}))\/rename\/?$/] = "/e/531e8942711f533cf0000019/rename";
The object above is mapping regex to testing value. I need to make something like the following:
for (var i in map) {
if (map.hasOwnProperty(i) && i.test(map[i])) {
console.log('It works');
}
}
But the code above doesn't work. What's wrong?
You can do:
var map = {};
map["^/e/(?:([0-9a-f]{24}))/rename/?$"] = "/e/531e8942711f533cf0000019/rename";
for (var i in map) {
if (map.hasOwnProperty(i) && (new RegExp(i)).test(map[i])) {
console.log('It works');
}
}
// prints: It works
Yes, you can; however, one thing to take note of is that regular expressions are first cast into a string before they're being used as a property name.
So when you want to use a property name as an expression again you must "rehydrate" it first:
for (var i in map) {
if (map.hasOwnProperty(i)) {
var re = eval(i);
if (re.test(map[i])) {
console.log('It works');
}
}
}
However, I would recommend using arrays instead to prevent this "magical" conversion to and fro:
var map = [];
map.push([/^\/e\/(?:([0-9a-f]{24}))\/rename\/?$/, "/e/531e8942711f533cf0000019/rename"]);
map.forEach(function(info) {
if (info[0].match(info[1])) {
console.log('it works');
}
});