Dynamic replacement of values with regular expression - javascript

I have some data in the form
[
{
"name": "alex",
"fullname": "Alessandro Magno"
},
{
"name": "alex",
"fullname": "Alessandro Magno"
}
]
but (name and fullname) are not fixed, they may be "key"/"value", or whatever.
I'm also given a template to follow, e.g.:
var template = "<span>data.fullname (data.name)</span>".
My problem is the following:
I have to look for all the "data." in the string,
obtain the value following it (in this case, fullname and name),
and replace data. with my external source. E.g.
str.replace("data.<value>", source[value]);
In Javascript.
Thanks!
EDIT: I probably explained it wrongly. My source is defined (in this case, a name/fullname list in JSON format). I also have a template to follow. I have to replace the syntax used in the template (which is "data." ['data.' is fixed]) with the correspondent value of the source. Hope this is clearer now!
Re-thanks!

A simple replace call using a string will only replace a single instance of a substring. You'll have to use a regular expression.
Looking at what you're trying to do, I'd say you're probably looking for something like:
var s = "<span>data.fullname (data.name)</span>";
var replacements = {name: 'alex', fullname: 'alessandro'};//example
s.replace(/(data\.)([a-z]+)/g, function(a,b,c)
{
return b + (repl[c] || 'none');
});
This results in "data.alessandro (data.alex)"
How it works? Central to this approach is the regular expression:
/(data\.)([a-z]+)/g, which is quite basic:
(data\.): match and capture the literal string "data."
([a-z]+): again: match & capture 1 or more chars fater data. -> "data."
g: is the global flag, apply this patter to the entire string.
Now, for each match for this pattern that is found, instead of providing a replacement string, I provide a function, that is passed the matched substring (and the captured groups as separate arguments), and use the function construct a replacement string:
function(a, b, c)
{//a -> entire substring, b-> data., c-> string after data.
return b + (replacements[c] || 'none');// logical || to provide default string replacement
}
It's as simple as that, really. Given that your values are contained by objects, that are in an array, you could opt to code the following:
var vals = [{name: 'alex', fullname: 'alessandro'},{name: 'alex2', fullname: 'alessandro2'}],
results =[],
template = "<span>data.fullname (data.name)</span>";
for (var i=0;i<vals.length;++i)
results[i] = template.replace(/(data\.)([a-z]+)/g, function(a,b,c)
{
return b + (vals[i][c] || 'default');
});
Edit:
To remove data. substring, too, change the callback function (and pattern) to:
s.replace(/data\.([a-z]+)/function(a,c)
{
return replacements[c] || 'none';
});
In case of the code above:
for (var i=0;i<vals.length;++i)
results[i] = template.replace(/data\.([a-z]+)/g, function(a,c)
{
return vals[i][c] || 'default';
});
Is what you're after

If you need to use a template you could use template engine. Basically it will allow you to bind an object to a template. Behind the scene the template is parsed using regex. Pseudo-code:
var template = "<span>{fullname} ({name})</span>";
var html = template({ fullname: data.fullname, name: data.name });
To name a few:
http://handlebarsjs.com/
http://mustache.github.io/
http://underscorejs.org/
Underscore is more a library tool belt, but it provides a simple templating engine that works well for common use.

It is not clear what the transformation you are trying to achieve is, but I can tell you that you should not be using regex to achieve it! Transform your JSON into JavaScript objects using JSON.parse, transform the objects directly, then convert back to JSON via JSON.stringify.

Related

Dynamic string cutting

Okay, so I have a filepath with a variable prefix...
C:\Users\susan ivey\Documents\VKS Projects\secc-electron\src\views\main.jade
... now this path will be different for whatever computer I'm working on...
is there a way to traverse the string up to say 'secc-electron\', and drop it and everything before it while preserving the rest of it? I'm familiar with converting strings to arrays to manipulate elements contained within delimiters, but this is a problem that I have yet to come up with an answer to... would there be some sort of regex solution instead? I'm not that great with regex so I wouldn't know where to begin...
What you probably want is to do a split (with regex or not):
Here's an example:
var paragraph = 'C:\\Users\\susan ivey\\Documents\\VKS Projects\\secc-electron\\src\\views\\main.jade';
var splittedString = paragraph.split("secc-electron"); // returns an array of 2 element containing "C:\\Users\\susan ivey\\Documents\\VKS Projects\\" as the first element and "\\src\\views\\main.jade" as the 2nd element
console.log(splittedString[1]);
You can have a look at this https://www.w3schools.com/jsref/jsref_split.asp to learn more about this function.
With Regex you can do:
var myPath = 'C:\Users\susan ivey\Documents\VKS Projects\secc-electron\src\views\main.jade'
var relativePath = myPath.replace(/.*(?=secc-electron)/, '');
The Regex is:
.*(?=secc-electron)
It matches any characters up to 'secc-electron'. When calling replace it will return the last part of the path.
You can split the string at a certain point, then return the second part of the resulting array:
var string = "C:\Users\susan ivey\Documents\VKS Projects\secc-electron\src\views\main.jade"
console.log('string is: ', string)
var newArray = string.split("secc-electron")
console.log('newArray is: ', newArray)
console.log('newArray[1] is: ', newArray[1])
Alternatively you could use path.parse(path); https://nodejs.org/api/path.html#path_path_parse_path and retrieve the parts that you are interested in from the object that gets returned.

Javascript: How to use Template Literals with JSON?

I discovered Javascript ES6 Template Literals today. Just one word: Awesome!
Question: How to store and load Template Literals as JSON? I load some files via XHR, followed by some JSON.parse() which doesn't support ` instead of ", so it seems one can't save Template Literals directly in the files.
Goal: To use this for dynamic strings and translation and to get rid of confusing stuff like ("Hello " + username + "! How are you?") which requires multiple strings to be stored for just one message, and instead save my stuff beautifully and simple as
`Hello, ${username}! How are you?`
where username points to the dynamic variable with the same name. Is that possible? If yes, how to achieve this? It's okay if i have to use a function to somehow convert the strings into Template Literals as long as it doesn't hit hard on the overall performance, but I would like to at least avoid eval.
You can create your own function to parse template literal,
function stringTemplateParser(expression, valueObj) {
const templateMatcher = /{{\s?([^{}\s]*)\s?}}/g;
let text = expression.replace(templateMatcher, (substring, value, index) => {
value = valueObj[value];
return value;
});
return text
}
console.log(stringTemplateParser('my name is {{name}} and age is {{age}}', {name: 'Tom', age:100}));
// output 'my name is Tom and age is 100'
You could always use JSON.stringify to enclose dynamic data:
const data = 'some value';
JSON.stringify({
data,
});
// expected: "{\"data\": \"some value\"}"
I found it easier to separate the problem in a few substrings of JSON. Create the key "message" and this key stores parts of the message. It also works well for i18n.
{
"message" : {
"_0": "first part ",
"_1": "after first variable. ",
"_2": "after another variable"
}
}
And then, after decoding it, you can access it like
${message._0}${variable}${message._1}${var2}${message._2}
Try json-templates. Looks like exactly what you're looking for.

Creating and populating a json object

I need to construct and populate a json object with values coming from a method.
A bit of background to this: I'm searching pdf documents with a designated keyword and if I find any match, for each match I need to save:
-the whole sentence where the match is found
-the search term (defined elsewhere: the search term is always the same, so it's really redundant here, but I might need it in the json object that's why I'm including it)
-the result (which is the index where the search term is found in a whole sentence and it should be an integer)
So, here is some code.
I have this function call inside a loop (the loops goes through the pages and then there is a second loop that goes through the text):
for(var i = 0; i < items.length; i++){
lineWithResult = searchPdf(block.str);
if(lineWithResult != null){
console.log(lineWithResult + " wordCounter is " + wordCounter);
}
}
and the function itself:
function searchPdf(toSearch){
var result = toSearch.toLowerCase().indexOf(searchTerm);
if(result >=0){//if match is found
wordCounter++;
//console.log("toSearch " + toSearch + " result is " + result + " wordCounter " + wordCounter);
return toSearch;
}
else{//if match not found
return null;
}
}
SO I need to construct a json object that at each iteration takes in the parameters discussed above:
So, what would be the best way - I'm a bit rusty with json?
I think I would start by creating an empty object like so (if that's even a valid definition):
var searchResult = {"Line" : "", "SearchTerm" : "", "Result" : ""}
If the above is right, where do I define the object and how do I fill it up with the relevant values? Bear in mind that there will be a lot of Lines, one search term and a lot of Results because the documents (a pdf) which I will use are quite big and can returns lots of matches
thanks
With saying something like that:
var searchResult = {"Line" : "", "SearchTerm" : "", "Result" : ""}
You have already defined the object. JavaScript (at this point) is prototypical, not a "class" based language. JSON in JavaScript is not much more than just a plain JavaScript object. If you want to to create multiple objects of that kind, you have various options. I recommend you to read about JS Object creational patterns.
Here is a good link.
That being said, you could do something like that:
// ... maybe inside a function
return {
line: myLineValue,
searchTerm: mySearchtermValue,
result: myResult
}
There is no need to init something with empty values; you just create the object with the curly brackets.
Hope this makes sense to you; if not, let me know in the comments, and I will try to improve my answer. :-)

String to Object

So basically I have this code:
var string = '{name: "bob", height: 4, weight: 145}';
I would like to know if it is possible to convert that string into an object.
so that I can use
string.name, string.height, and string.weight
(I am retrieving the string variable from a database so I cannot just remove the quotes and make it an object in the first place)
eval, as suggested by Igor, will certainly work but is vulnerable to attack.
Instead you could use a library to parse it for you. There are options in the following link:
Eval is evil... So what should I use instead?
It seems that your string is malformed. In order to work with JSON.parse or even jQuery.parseJSON methods, your keys must have speech marks (" ) around them, like so:
var str = '{"name": "bob", "height": 4, "weight": 145}';
var obj = JSON.parse(str);
You can test this by adding console.log(obj);​ as the final line. Here is my jsFiddle example.
So try to see if you can pull down the data from the server in the format I have suggested and it can then easily be parsed into a JavaScript object.
I would not use string for a variable name, but:
var obj = eval(string);
alert(obj.name);
or you can use jQuery.parseJSON: api.jquery.com/jQuery.parseJSON.

convert "converted" object string to JSON or Object

i've following problem and since i upgraded my prototypeJS framework.
the JSON parse is not able anymore to convert this string to an object.
"{empty: false, ip: true}"
previously in version 1.6 it was possible and now it needs to be a "validated" JSON string like
'{"empty": false, "ip": true}'
But how can i convert the 1st example back to an object?
JSON needs all keys to be quoted, so this:
"{empty: false, ip: true}"
is not a valid JSON. You need to preprocess it in order to be able to parse this JSON.
function preprocessJSON(str) {
return str.replace(/("(\\.|[^"])*"|'(\\.|[^'])*')|(\w+)\s*:/g,
function(all, string, strDouble, strSingle, jsonLabel) {
if (jsonLabel) {
return '"' + jsonLabel + '": ';
}
return all;
});
}
(Try on JSFiddle) It uses a simple regular expression to replace a word, followed by colon, with that word quoted inside double quotes. The regular expression will not quote the label inside other strings.
Then you can safely
data = JSON.parse(preprocessJSON(json));
It makes sense that the json parser didn't accept the first input as it is invalid json. What you are using in the first example is javascript object notation. It's possible to convert this to an object using the eval() function.
var str = "({empty: false, ip: true})";
var obj = eval(str);
You should of course only do this if you have the guarantees the code you'll be executing is save.
You can find more information about the json spec here. A json validator can be found here.
edit: Thai's answer above is probably a better solution
const dataWithQuotes = str.replace(/("(\\.|[^"])*"|'(\\.|[^'])*')|(\w+)\s*:/g, (all, string, strDouble, strSingle, jsonLabel) => {
if (jsonLabel) {
return `"${jsonLabel}": `;
}
return all;
});
return dataWithQuotes
similar solution as above , but updated with arrow functions.

Categories