Parsing string into dictionary - javascript

i would like to transform in an elegent way this kind of string :
"{lastname=Oba, firstname=Bar}"
to
var person = [];
person["firstName"] = "Bar";
person["lastName"] = "Oba";
I try with JSON parse but not working,
i don't know how to that without dirty spliting

Algorithm:
splitting string by , you'll get a list of A=B pairs, then split each pair of the list by = and form dictionary:
Python
s = "{lastname=Oba, firstname=Bar}"
l = s[1:-1].split(",")
d = {}
for e in l:
a = e.split("=")
d[a[0].strip()] = a[1].strip()
JavaScript
var s = "{lastname=Oba, firstname=Bar}";
var l = s.slice(1,-1).split(',');
var d = {};
for (var i in l) {
var a = l[i].split('=');
d[a[0].trim()] = a[1].trim();
}

This code should easily parse this.
function myParser(str) {
return str.slice(1, -1).split(',').map(function(el) {
return el.trim()
}).map(function(el) {
return el.split('=')
}).reduce(function(result, pair) {
result[pair[0].trim()] = pair[1].trim();
return result
}, {});
}
It will work as expected only for small group of properties and datas, but figuring these cases and fixing that behaviour is leaved as exercise for reader.

Related

How do I convert a string to a dictionary in javascript?

I have a string
var str = "1:6,5,2,2:3";
I want to convert this str into a js dictionary such that:
var dict = {1:"6,5,2",
2:"3"};
so that I can fetch the values by their respective key index. How do I convert it?
I had tried this code to store the splitted values into an array:
var pages = "1:6,5,2,2:3";
var numbers = [];
if (pages.includes(',')) {
page_nos = pages.split(',');
for (var i = 0; i < page_nos.length; i++) {
if (page_nos[i].includes(':')) {
var n = page_nos[i].split(':');
numbers.push(n[1]);
} else {
numbers.push(page_nos[i]);
}
}
} else {
page_nos = pages.split(':');
numbers.push(page_nos[1])
};
console.log('numbers: ', numbers);
But it's incorrect, as without dictionary it's impossible to know what value belongs to which index
If you cannot make your input string a proper JSON or another easily parsable format in the first place, this answers your question:
const str = "1:6,5,2,2:3";
const obj = str.split(/,(?=\d+:)/).reduce((accu, part) => {
const [k, v] = part.split(':', 2);
accu[k] = v;
return accu;
}, {});
console.log(obj);
Cut the string at all commas that are followed by digits and a colon. Each part has a key in front of a colon and a value after it, which should be stuffed in an object in this format.
No mutations solution.
const str = "1:6,5,2,2:3";
const dict = str
.split(/(\d+:.*)(?=\d+:)/g)
.reduce((t, c) => {
const [key, value] = c.replace(/,$/, "").split(/:/);
return { ...t, [key]: value }
});
console.log(dict);
if you consider not using regular expression, you might try this as well.
to take out a dict (Object) from that string, this will do.
var pages = "1:6,5,2,2:3";
function stringToObject(str) {
var page_object = {};
var last_object;
str.split(",").forEach((item) => {
if (item.includes(":")) {
page_object[item.split(":")[0]] = item.split(":")[1];
last_object = item.split(":")[0];
} else {
page_object[last_object] += `,${item}`;
}
});
return page_object;
}
console.log(stringToObject(pages))
Presented below may be one possible solution to achieve the desired objective.
NOTE:
In lieu of var the code uses either let or const as applicable.
Code Snippet
const pages = "1:6,5,2,2:3";
const resObj = {};
let page_nos, k;
if (pages.includes(',')) {
page_nos = pages.split(',');
for (let i = 0; i < page_nos.length; i++) {
if (page_nos[i].includes(':')) {
let n = page_nos[i].split(':');
k = n[0];
resObj[k] = n[1].toString();
} else {
resObj[k] += ", " + page_nos[i].toString();
}
}
} else {
page_nos = pages.split(':');
resObj[page_nos[0]] = [page_nos[1]]
numbers.push(page_nos[1])
};
console.log('result object: ', resObj);
This code essentially fixes the code given in the question. It is self-explanatory and any specific information required may be added based on questions in comments.
You could take nested splitring for entries and get an object from it.
const
str = "1:6,5,2,2:3",
result = Object.fromEntries(str
.split(/,(?=[^,]*:)/)
.map(s => s.split(':'))
);
console.log(result);

what is the best way to extract variables with '=' from a string in javascript

I want to extract the variables names from a string like this: "foo=valor bar=second", and so on.
To return:
{
foo: "valor",
bar: "second",
...
}
You can use Regex Look Aheads to check for a variable name that is preceded by an = symbol
var str = "foo=valor bar=second";
var varRegex = /\w+(?=(\s)*(\=))/g;
var valueRegex = /(?<=(\=)[\s'"]*)\w+/g;
var varArr = str.match(varRegex);
var valueArr = str.match(valueRegex);
console.log(valueArr);
let obj = {};
for(let i in varArr) {
obj[varArr[i]] = valueArr[i];
}
console.log(obj);
var str = "foo=valor,bar=second";
var obj = {};
str.split(",").forEach(
function(item){
if(item){
var vars = item.split("=");
obj[vars[0]] = vars[1]
}
});
console.log(obj)
Different approach from the previous answer: You can split the string on spaces and then map the result array, splitting on the equal sign to create your object (left side is property, right side is value)
If you need it your specific format you can reduce it to convert the array into one big object with all the values
let a = "foo=valor bar=second"
console.log(a.split(' ').map((i,v) => { return JSON.parse(`{"${i.split('=')[0]}": "${i.split('=')[1]}"}`);}))
let b = a.split(' ').map((i,v) => { return JSON.parse(`{"${i.split('=')[0]}": "${i.split('=')[1]}"}`);})
console.log(b.reduce(function(acc, x) {
for (var key in x) acc[key] = x[key];
return acc;
}));
Not necessarily the quickest answer (in terms of speed of submission), but less regular expressions to maintain and less variables to store.
function toJSON(str) {
const regex = /(\w+)\=(\w+)\s*/g;
let result = {};
let match;
while (match = regex.exec(str)) {
result[match[1]] = match[2];
}
return result;
}
console.log(toJSON("foo=valor bar=second"));

Create nested Javascript Object dynamically

I have got a . (dot) separated string, from which I want to create nested JSON object. The length of the string is not fixed. For example,
var string = 'a.b.c.d';
Then my JSON object should be as following:
a: {
b: {
c:{
d: {
//Some properties here.
}
}
}
}
I've tried following code:
var packageName = "a.b.c.d"
var splitted = packageName.split('.');
var json = {};
for(var i=0;i<splitted.length-1;i++){
json[splitted[i]] = splitted[i+1];
}
But this returns
{
a: 'b',
b: 'c',
c: 'd'
}
But this is not what I want. I've also searched on google and found similar questions, but no solutions answer my problem. For example this.
A good use case for reduce
packageName = "a.b.c.d";
initProps = {hi: 'there'};
obj = packageName.split('.').reduceRight((o, x) => ({[x]: o}), initProps);
console.log(JSON.stringify(obj))
If you find loops easier to work with, a loop could be written concisely as
result = {};
ptr = result;
for (let prop of packageName.split('.'))
ptr = ptr[prop] = {};
You need to create a new object each time and attribute it to the last object created. And it goes until splitted.length, not splitted.length - 1, because you're using <, not <=.
var packageName = "a.b.c.d";
var splitted = packageName.split('.');
var json = {};
var current = json;
for (var i = 0; i < splitted.length; i++) {
current[splitted[i]] = {};
current = current[splitted[i]];
}
console.log(json);
You may use the last splittted part as property for some payload.
I suggest to keep the object reference and use a temporary variable for aceessing an creating a new property, if necessary.
Please avoid the use of JSON for not stringified objects.
var packageName = "a.b.c.d",
splitted = packageName.split('.'),
result = {},
temp = result,
i;
for (i = 0; i < splitted.length - 1; i++) {
temp[splitted[i]] = temp[splitted[i]] || {};
temp = temp[splitted[i]];
}
temp[splitted[i]] = { some: 'data' };
console.log(result);

How can I capture a hash to Object in functional JavaScript?

I'm writing a piece of code in JavaScript for modern browser. I'm not using lodash or underscore as we want to keep the library as small as possible.
For example,
If the url comes like this. http://something.com/#hash=value
And the app is configured to capture key hash then the result would be this. Nothing fancy. I was just wondering if there's a better way or simple way to do this.
{
'hash': 'value'
}
The code
var config = Object.assign({}, {
capturedHashParams: ['hash']
});
var hashValue = '#hash=value1'.substr(1);
var capturedHashParams = {};
if (config.capturedHashParams && Array.isArray(config.capturedHashParams)) {
var splitedHash = hashValue.split('=');
if (splitedHash.length > 0) {
var key = splitedHash[0] || '';
var value = splitedHash[1] || '';
if (key && value) {
config.capturedHashParams.forEach(function(hp) {
if (hp.toLowerCase().indexOf(key.toLowerCase()) > -1) {
capturedHashParams[key] = value;
}
});
}
}
}
console.log(capturedHashParams);
https://jsfiddle.net/c92p0rfm/2/
i think you are watching for something like this:
var output = [];
var hashString = window.location.hash;
var hashArray = hash.split('&');
for(var index = 0; index < hashArray.length; index++){
var text = hashArray[index];
var tempArray= text.split('=');
var object = {
id: tempArray[0],
value: tempArray[1]
};
output[index] = object;
}
now output looks like this:
[
{
id: "hash",
value: "value"
}
]
Your question is somewhat ambiguous. It appears that you want to extract key/value pairs from an url hash and return as a JavaScript object. I am bit uncertain about whether you want to extract all key/value pairs or only those provided in a config object. I am also a bit uncertain as to whether you want a solution within a strict functional programming paradigm, or just a plain solution with a small code footprint. I will assume the latter.
A straightforward approach to capture all key/value pairs:
var url = 'http://something.com/#hash=value&anotherHash=value';
//extract key=value pairs from url
var params = url.split('#').pop().split('&');
//assign to data object
for(var data = {}, i = 0, temp; i < params.length; i++){
// extract array [key, value]
temp = params[i].split('=');
// assign to data object
data[temp[0]] = temp[1];
}
console.log(data);
A more compact solution to do the same with .reduce():
var url = 'http://something.com/#hash=value&anotherHash=value';
var data = url
.split('#')
.pop()
.split('&')
.reduce(function(obj, keyval){
keyval = keyval.split('=');
obj[keyval[0]] = keyval[1];
return obj;
}, {});
console.log(data)
If you want to configure which keys to extract:
var url = 'http://something.com/#hash=value&anotherHash=value&notThisHash=value';
//config object
var keysToCapture = [
'hash',
'anotherHash'
];
var data = url
.split('#')
.pop()
.split('&')
.reduce(function(obj, keyval){
keyval = keyval.split('=');
if(keysToCapture.indexOf(keyval[0]) > -1){
obj[keyval[0]] = keyval[1];
}
return obj;
}, {});
console.log(data)
Which you could capture in a reusable function like this:
function extractParamsObject(url, keysToCapture){
return url
.split('#')
.pop() //hash/fragment: everything after the last #
.split('&')
.reduce(function(obj, keyval){
keyval = keyval.split('=');
if(keysToCapture.indexOf(keyval[0]) > -1){
obj[keyval[0]] = keyval[1];
}
return obj;
}, {});
}
console.log(extractParamsObject(
'http://something.com/#hash=value&anotherHash=value&notThisHash=value',
['hash', 'anotherHash']
));

Create deep object from string like "obj.obj1.obj2.data'

I'm starting with unit testing. I need to create some fake data to run the tests. So let's say inside a stubbed method I'm passing an obj as an argument and I do things with obj.obj1.obj2.data inside the function. Is there a way to set this fake object? So, given:
obj.obj1.obj2.data
It creates:
obj = {
obj1: {
obj2: {
data: 'whatever'}}}
So it would be at the end something like:
var obj = creator('obj.obj1.obj2.data', 20);
Assuming the string is only a set of objects (no arrays) this should be fairly straightforward. Just split the input string on . and then use a while loop to do the nesting.
function creator(str,val){
var tree = str.split('.');
var ret = {};
var cur = ret;
while(tree.length){
var name = tree.shift();
cur[name] = tree.length ? {} : val;
cur = cur[name];
}
return ret;
}
document.querySelector("#out").innerHTML = JSON.stringify(creator('obj.obj1.obj2.data',20));
<div id="out"></div>
Just in case anyone else in interested, I created a simple npm module with the function below (https://github.com/r01010010/zappy) check it out:
var objFrom = function(str, last_value){
var objs = str.split('.');
var r = {};
var last = r;
for(i=0; i < objs.length; i++) {
if(i !== objs.length - 1){
last = last[objs[i]] = {};
}else{
last[objs[i]] = last_value;
}
}
return r;
}
var obj = objFrom('obj1.obj2.data', 20);
console.log(obj.obj1.obj2.data);

Categories