Why do we need to add parentheses to eval JSON? [duplicate] - javascript

This question already has answers here:
Why does JavaScript's eval need parentheses to eval JSON data?
(7 answers)
Closed 8 years ago.
Why does the following code needs to add ( and ) for eval?
var strJson = eval("(" + $("#status").val().replace(";","") + ")");
PS: $("#status").val() is returning something like {"10000048":"1","25000175":"2","25000268":"3"};

It depends what the value in that element is (an unknown), wrapping it in () is the safe route to account for possibly of no input being there.
Edit: Now that you've cleared up it's JSON, this isn't valid:
eval('{"10000048":"1","25000175":"2","25000268":"3"}');
But this will result in a valid object being returned:
eval('({"10000048":"1","25000175":"2","25000268":"3"})');
//effectively:
eval('return {"10000048":"1","25000175":"2","25000268":"3"};');
Picture in a JavaScript file:
<script type="text/javascript">
{"10000048":"1","25000175":"2","25000268":"3"}
</script>
This is going to fail, it's just an object declared inline but not proper syntax...the same reason a server has to support JSONP for it to work.
A bit tangential to the question, but since you're including jQuery, you might as well use $.parseJSON() (which will use the native JSON.parse() if available) for this:
var strJson = $.parseJSON($("#status").val().replace(";",""));

eval takes a JavaScript statement or expression, but {...} would be valid as a statement or an expression, and the grammar of JavaScript prefers a statement.
As an expression:
{"10000048":"1","25000175":"2","25000268":"3"}
is an Object with some properties (what you want).
As a statement, it is a block:
{ // begin Block
"10000048": // LabelledStatement (but the quotes are invalid)
"1", // Expression, calculate string "1" then discard it, then
"25000175": // you can't put a label inside an expression
which gives an error.
(JavaScript labels can be used to label a particular statement for use with break/continue. They're a bit pointless and almost never used.)
So by adding the parentheses you resolve the ambiguity. Only an expression can start with (, so the contents are parsed in an expression context, giving an object literal, not a statement context.
Incidentally this is not quite enough to correctly interpret all possible JSON values. Due to an oversight in JSON's design, the characters U+2028 and U+2029, two obscure Unicode line-ending characters, are valid to put unescaped in a JSON string literal, but not in a JavaScript string literal. If you want to be safe, you can escape them, eg:
function parseJSON(s) {
if ('JSON' in window) return JSON.parse(s);
return eval('('+s.replace(/\u2028/g, '\\u2028').replace(/\u2029/g, '\\u2029')+')');
}

Related

JavaScript string normalize() does not work in some cases - why?

In my debugger I can see an object is retrieved with a unicode character. e.g.
{
name: "(Other\uff09"
}
If this object is referenced using the var myObj in the debugger I see that
myObj.name.normalize()
returns
"(Other\uff09"
If instead I use
"(Other\uff09".normalize()
it returns
"(Other)"
Why?
I've learnt a little since posting this question. Initially I thought that \uff09 was equivalent to ). It's not, instead it's ), aka Full Width Right Parenthesis.
This essentially means that the opening and closing brackets do not match. e.g. ( is not closed by ). This is causing parsing issues for the NodeMailer AddressParser module I'm using.
To normalize it I'm using
JSON.parse(`"(Other\uff09"`).normalize("NFKC")
which translates the string to (Other) rather than (Other).
Breaking this down
JSON.parse(`"(Other\uff09"`)
where the double quotes is required, produces (Other). i.e. It converts the unicode escape characters into the character they represent.
Then
.normalize("NFKC")
converts that into (Other).
This worked for me in this sample. I still need to see if it scales up.

Javascript eval fails on complicated json array [duplicate]

This question already has answers here:
JSON Javascript escape
(4 answers)
Closed 7 years ago.
I want to convert a json string to object by eval, but it fails with error like:
Uncaught SyntaxError: Unexpected identifier VM250:1
below is my string:
'[{"quiz_id":"3","_id":"1","option_in_json":"[{\"option\":\"1\",\"is_answer\":false},{\"option\":\"2\",\"is_answer\":true}]","question":"1+1"}]';
Seems there is something wrong in the bold part, but i don't know how to fix it
The code below is not working
var m='[{"quiz_id":"3","_id":"1","option_in_json":"[{\"option\":\"1\",\"is_answer\":false},{\"option\":\"2\",\"is_answer\":true}]","question":"1+1"}]';
eval(m);
The code below is working so i think the data structure of this json string is ok
var m=[{"quiz_id":"3","_id":"1","option_in_json":"[{\"option\":\"1\",\"is_answer\":false},{\"option\":\"2\",\"is_answer\":true}]","question":"1+1"}];
alert(m[0].option_in_json);
Also tried with $.parseJSON with no luck
It does not work because you are not escaping the data inside the string literal correctly. Look at the value of m in the first case, especially the quotation marks:
[{"option_in_json":"[{"option":"1","is_answer":false}]","question":"1+1"}]
// ^ ^
I removed some irrelevant data. You should be able to see that this cannot be valid JavaScript (or JSON), because the quotation mark before option terminates the string.
In order to put the data inside a string literal, you should either fix the data so that it doesn't contain nested JSON, or escape \:
'[{"option_in_json":"[{\\"option\\": ... }]"}]'
Better of course if you are not putting it in a string literal in the first place.
var m='[{"quiz_id":"3","_id":"1","option_in_json": [{"option":"1","is_answer":false},{"option":"2","is_answer":true}],"question":"1+1"}]';
// ^-- don't wrap in "" so no need to escape inner double quotes.
console.dir(JSON.parse(m));

Getting functions content with regex

I'm trying to get the functions from an input string by using regular expressions.
So far, I managed to get the JavaScript kind of function declarations with the following regex:
/(\b(f|F)unction(.*?)\((.*?)\)\s*\{)/g
Which when applied like this, will return me whole declaration on the first index:
var re = /(\b(f|F)unction(.*?)\((.*?)\)\s*\{)/g;
while ((m = re.exec(text)) !== null) {
//m[0] contains the function declaration
declarations.push(m[0]);
}
Now, I would like to get in the returned match, the whole content of each of the functions so I can work with it later on (removed it, wrap it...)
I haven't managed to find a regext to do so, so far, I got this:
(\b(f|F)unction(.*?)\((.*?)\)\s*\{)(.*?|\n)*\}
But of course, it catches the first closing bracket } instead of the one at the end of each of the functions.
Any idea of how to get the closing } of each function?
Any idea of how to get the closing } of each function?
This will be very hard with a regex. Because the function body can include any number of possibly nested brace pairs. And then consider strings containing unmatched braces in the function body.
To parse a non-regular language you need something more powerful than regular expressions: a parser for that language.
(Some regex variants have some ability to matched paired characters, but firstly JavaScript's regex engine isn't one; and secondly then there are those strings….)

Parsing malformed JSON in JavaScript

Thanks for looking!
BACKGROUND
I am writing some front-end code that consumes a JSON service which is returning malformed JSON. Specifically, the keys are not surrounded with quotes:
{foo: "bar"}
I have NO CONTROL over the service, so I am correcting this like so:
var scrubbedJson = dirtyJson.replace(/(['"])?([a-zA-Z0-9_]+)(['"])?:/g, '"$2": ');
This gives me well formed JSON:
{"foo": "bar"}
Problem
However, when I call JSON.parse(scrubbedJson), I still get an error. I suspect it may be because the entire JSON string is surrounded in double quotes but I am not sure.
UPDATE
This has been solved--the above code works fine. I had a rogue single quote in the body of the JSON that was returned. I got that out of there and everything now parses. Thanks.
Any help would be appreciated.
You can avoid using a regexp altogether and still output a JavaScript object from a malformed JSON string (keys without quotes, single quotes, etc), using this simple trick:
var jsonify = (function(div){
return function(json){
div.setAttribute('onclick', 'this.__json__ = ' + json);
div.click();
return div.__json__;
}
})(document.createElement('div'));
// Let's say you had a string like '{ one: 1 }' (malformed, a key without quotes)
// jsonify('{ one: 1 }') will output a good ol' JS object ;)
Here's a demo: http://codepen.io/csuwldcat/pen/dfzsu (open your console)
something like this may help to repair the json ..
$str='{foo:"bar"}';
echo preg_replace('/({)([a-zA-Z0-9]+)(:)/','$1"$2"${3}',$str);
Output:
{"foo":"bar"}
EDIT:
var str='{foo:"bar"}';
str.replace(/({)([a-zA-Z0-9]+)(:)/,'$1"$2"$3')
There is a project that takes care of all kinds of invalid cases in JSON https://github.com/freethenation/durable-json-lint
I was trying to solve the same problem using a regEx in Javascript. I have an app written for Node.js to parse incoming JSON, but wanted a "relaxed" version of the parser (see following comments), since it is inconvenient to put quotes around every key (name). Here is my solution:
var objKeysRegex = /({|,)(?:\s*)(?:')?([A-Za-z_$\.][A-Za-z0-9_ \-\.$]*)(?:')?(?:\s*):/g;// look for object names
var newQuotedKeysString = originalString.replace(objKeysRegex, "$1\"$2\":");// all object names should be double quoted
var newObject = JSON.parse(newQuotedKeysString);
Here's a breakdown of the regEx:
({|,) looks for the beginning of the object, a { for flat objects or , for embedded objects.
(?:\s*) finds but does not remember white space
(?:')? finds but does not remember a single quote (to be replaced by a double quote later). There will be either zero or one of these.
([A-Za-z_$\.][A-Za-z0-9_ \-\.$]*) is the name (or key). Starts with any letter, underscore, $, or dot, followed by zero or more alpha-numeric characters or underscores or dashes or dots or $.
the last character : is what delimits the name of the object from the value.
Now we can use replace() with some dressing to get our newly quoted keys:
originalString.replace(objKeysRegex, "$1\"$2\":")
where the $1 is either { or , depending on whether the object was embedded in another object. \" adds a double quote. $2 is the name. \" another double quote. and finally : finishes it off.
Test it out with
{keyOne: "value1", $keyTwo: "value 2", key-3:{key4:18.34}}
output:
{"keyOne": "value1","$keyTwo": "value 2","key-3":{"key4":18.34}}
Some comments:
I have not tested this method for speed, but from what I gather by reading some of these entries is that using a regex is faster than eval()
For my application, I'm limiting the characters that names are allowed to have with ([A-Za-z_$\.][A-Za-z0-9_ \-\.$]*) for my 'relaxed' version JSON parser. If you wanted to allow more characters in names (you can do that and still be valid), you could instead use ([^'":]+) to mean anything other than double or single quotes or a colon. You can have all sorts of stuff in here with this expression, so be careful.
One shortcoming is that this method actually changes the original incoming data (but I think that's what you wanted?). You could program around that to mitigate this issue - depends on your needs and resources available.
Hope this helps.
-John L.
How about?
function fixJson(json) {
var tempString, tempJson, output;
tempString = JSON.stringify(json);
tempJson = JSON.parse(tempString);
output = JSON.stringify(tempJson);
return output;
}

Javascript object property quotes [duplicate]

This question already has answers here:
What is the difference between object keys with quotes and without quotes?
(5 answers)
Closed 5 years ago.
Let's say I have the following object:
var VariableName = {
firstProperty: 1,
secondProperty: 2
}
Do I have to wrap the object properties in quotes like this?
var VariableName = {
'firstProperty': 1,
'secondProperty': 2
}
Is this Single quotes in JavaScript object literal the correct answer?
No, you don't need to do that.
The only reasons to quote object-keys are
the property name is reserved/used by the browser/js engine (eg. "class" in IE)
you have special characters or white spaces in your key
so for instance
var VariableName = {
"some-prop": 42, // needs quotation because of `-`
"class": 'foobar' // doesn't syntatically require quotes, but it will fail on some IEs
valid: 'yay' // no quotes required
};
You only have to use the quotes around the property, if the property name is a reserved word (like for, in, function, ...). That way you prevent Javascript from trying to interpret the keyword as a part of the language and most probably get a syntax error.
Furthermore, if you want to use spaces in property names, you also have to use quotes.
If your property names are just normal names without any collusion potential or spaces, you may use the syntax you prefer.
One other possibility that requires quotes is the use of Javascript minifiers like google closure compiler, as it tends to replace all property names. If you put your property names in quotes, however, the closure compiler preserves the property as you coded it. This has some relevance when exporting objects in a library or using an parameter object.
Property names in object literals must be strings, numbers or identifiers. If the name is a valid identifier, then you don't need quotes, otherwise they follow the same rules as strings.
firstProperty and secondProperty are both valid identifiers, so you don't need quotes.
See page 65 of the specification for more details.
For Javascript you usually do not have to use quotes. You may use ' or " if you like, and you must use quotes if there is a clash between the name of your property and a JS reserved word like null. The answer you linked to seems to be correct, yes.
For JSON, you should use " around strings (including object property names)

Categories

Resources