5

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.

2
  • 4
    I hate myself for saying this, but maybe eval is what you're looking for? Commented Jul 26, 2016 at 16:12
  • Thanks, it is indeed, I didn't think about it. Eval is too powerful :) Commented Jul 26, 2016 at 16:22

2 Answers 2

10

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:

  1. It allows arbitrary code execution. So you really have to trust the text you're evaling. Don't eval user input.

  2. 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.

Sign up to request clarification or add additional context in comments.

8 Comments

That's a big "if" ;-)
Also, I think it will prevent JIT optimization.
@JoachimSauer: Yeah, I tried to mark it up fairly large. :-) The question suggests that it may well be the case here.
@EmileBergeron: Ah, yes, it's worth calling that bit out. I'll do that. Unlikely to be an issue, but still.
Didn't you answer the same question the same way a week or two ago? Or are you getting like me and finding it harder and harder to find old questions and answers, even the ones you wrote?
|
1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.