I know how to parse a valid JSON string : JSON.parse('{"key" : "value"}')
.
But what about a valid JS object, but invalid JSON, like : JSON.parse("{ key : 'value'}")
?
The example above throws :
Uncaught SyntaxError: Unexpected token k in JSON at position 2
My actual goal is even trickier. I want to parse a string of a JS object containing RegEx (unsupported by JSON but supported by JS) into a JS object :
'{ key1 : /val1/g , key2 : /val2/i }'
I eventually want to use this object with Mongoose and find documents with it :
Model.find({
key1 : /val1/g ,
key2 : /val2/i
})
I have tried applying a fairly complex RegEx to my String, replacing /val1/g
with new RegEx("val1","i")
:
str = str.replace( /\/(.+?)\/(g?i?).+?(?=,|})/g , "new RegExp(`$1`,`$2`)" )
The .replace()
operation works and modifies the string the way I want it. It yields :
{ key1 : new RegExp("val1","g") , key2 : new RegExp("val2","i") }
But when I try to apply JSON.parse
to it, it still fails because new RegEx("val1","i")
is not a valid value.
If you control and can trust the text you're converting, you can use eval
:
var str = '{ key1 : /val1/g , key2 : /val2/i }';
var obj = eval("(" + str + ")");
console.log(obj.key1);
Note that when doing the eval
, since your expression starts with {
, you have to wrap it in ()
so the parser knows that's starting an object initializer, not a block.
A couple of notes about eval
:
It allows arbitrary code execution. So you really have to trust the text you're eval
ing. Don't eval
user input.
Code in an execution context directly containing a call to eval
basically cannot be optimized, because the JavaScript engine can't know, when parsing the code, what the string will contain. So while I suppose technically it's premature optimization, I'd tuck the above off in a function that you call from your main logic rather than embedding it in your main logic directly.
I faced simmilar issue and solved it with the help of split and reduce.
const getObjectFromString = (stringToParse) => {
if(typeof stringToParse === 'string'){
let currentKey = '';
const keyValPairArr = stringToParse.replace('{','').replace('}','').split(':');
return keyValPairArr.reduce((obj,current,index,arr)=>{
const previousKey = currentKey;
const arrKeyVal = current.trim().split(',');
currentKey = index!==arr.length-1?arrKeyVal.pop().trim():'';
const previousVal = arrKeyVal.join(',');
if(previousKey&&previousVal!=='')obj[previousKey]=previousVal;
return obj;
},{})
}else{
return stringToParse||{};
}
}
// following are some results
const example1 = getObjectFromString('{first : 1, second : 2nd, third: "third, 3rd" }')
console.log(example1) // output: {first: '1', second: '2nd', third: '"third, 3rd"'}
It returns either empty object or the converted object from the passed string.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With