First of all: I know that there are many questions related to escaping, but I did not found a generally working answer so far.
Say I have this simple toy function for demonstration:
function f(somePOJO) {
var s = eval("'" + JSON.stringify(somePOJO) + "';"); // for demonstration only
return JSON.parse(s);
}
const clone = f({a: 1, b: "c"});
Given an object literal such as {a: 1, b: "c"} (a POJO), f should return a "clone" of it. (Note that I do not really use this approach for cloning or similar, and I am aware that eval is evil and also that it is not even needed here, it's just for demonstration of the escaping problem!)
This works fine, but only as long as the POJO values do not contain a '. Now of course I could escape the JSON by using something like JSON.stringify(somePOJO).replace(/'/g, "\\'"). This works if the POJO values contain ', but not if they contain \\'. And this creates a spiral of escaping...
Is there a solution to this at all?
The escape function to preserve a JSON string through being evaluated by the eval function, the JavaScript compiler under some circumstances or by the JSON.parse function is actually JSON.stringify. This JSON method will happily stringify string values, not just object data types.
function f(somePOJO) {
var s = eval( JSON.stringify(JSON.stringify(somePOJO)) );
return JSON.parse(s);
}
const obj = {a: 1, b: "c", d: "back\\, forward/"}
const clone = f(obj);
console.log(obj);
console.log(clone);
The reason it's not one of the escape/encodeURI/encodeURIComponent family of functions is that these are for escaping characters for inclusion in URLs whereas this case is about escaping characters to be parsed by a JavaScipt parser.
In most cases, particularly to parse JSON text using JSON.parse, stringifying JSON text a second time and parsing it twice is simply unnecessary.
Of somewhat academic interest now but before the introduction of JSON into Javascript, one could stringify a string by serially inspecting its characters and backslash escaping backslashes, at least one kind of quote marks, and unicode escaping control codes - the posted question may be missing the part about needing to escape backslash characters as well as quote marks.
I should construct and pass following text in my JSON scheme. Here is how it should look:
r"""any-text-goes-here"""
Here is how I decided to construct it:
function make(text) {
return `r"""${text}"""`;
}
The function above takes any string and converts it to desired format. But, when I return it in my API as one of fields of JSON, it looks like following:
"r\"\"\"any-text-goes-here\"\"\""
I want to avoid backslashes. I understand that those slashes is needed by Javascript to properly work, but can I remove them, because client side awaits how I described above. Is it possible technically? How can I solve problem?
JSON strings are delimited by " characters.
" characters can be included in a JSON string only by using an escape sequence.
Escape sequences start with a \.
You can't avoid the backslashes.
See the grammar from the JSON website:
I am creating an JSON file which stores some Physics equation, which will be rendered using MathJax.
"equations": [
"$w = F.s\cos\theta$"
]
I am getting a bad string error. I have tried adding another backslash before the slashes but that changes the equations drastically.
Is there any way to fix this issue without changing the equation
There were two issues you were falling over.
Firstly, a valid JSON file will have { and } around it (as David Gatti mentions in his answer, it is an object after all). Secondly, certain characters - including backslashes - will need to be escaped. When you parse it back into an object, the additional backslashes will be removed.
Your corrected JSON should read:
{
"equations": [
"$w = F.s\\cos\\theta$ "
]
}
JSON is an encoding of structured data. You write
{
"equations": [
"$w = F.s\\cos\\theta$"
]
}
to mean an object with a property named equations with an array with a single string:
$w = F.s\cos\theta$
The escaped backslashes (\) does not change the underlying data. They get removed by the receiver when the JSON gets decoded into the object graph.
I am generating the following string with JavaScript:
"ISCP\x00\x00\x00\x10\x00\x00\x00\x09\x01\x00\x00\x00\x00\!1PWR01\x0D\x0A"
It represents a chain of text and Hex values.
In fact the actual underlying string is built up like this:
"ISCP\\x00\\x00\\x00\\x10\\x00\\x00\\x00\\x09\\x01\\x00\\x00\\x00\\x00\\!1PWR01\\x0D\\x0A"
As I have to escape the slashes to be able to work with them in the first place.
Now I have to somehow transform this string into a into a string of chained Hex values so that I can send it across a TCP connection.
The result would look something like this:
\x49\x53\x43\x50\0\0\0\x10\0\0\0\t\x01\0\0\0\0\x21\x31\x50\x57\x52\x30\x31\r\n
But I don't know how to go about this.
You can use a regex to find all the \xHH-style sequences in your string and replace them with actual values. Since you cannot dynmically create literal \xHH escape sequences, you'll need to use a replacer callback with String.fromCharCode:
var newString = myString.replace(/\\x([0-9A-F][0-9A-F])/g, function(m, g1) {
return String.fromCharCode(parseInt(g1, 16));
});
This parses the two digits following each \x as a base-16 value, and then uses that number as a character code to create a new one-character string.
I am using jQuery's getJSON function to make a request and handle the JSON response. The problem is the response I get back is malformed and I can't change it. The response looks something like this:
{
aNumber: 200,
someText: '\'hello\' world',
anObject: {
'foo': 'fooValue',
'bar': '10.0'
}
}
To be valid JSON, it should look like this:
{
"aNumber": 200,
"someText": "'hello' world",
"anObject": {
"foo": "fooValue",
"bar": "10.0"
}
}
I would like to change the text returned to a valid JSON object. I've used the JavaScript replace function to turn the single quotes into double quotes and the escaped single quotes into single quotes, but now I am stuck on figuring out the best way to add quotes around the key values.
For example, how would I change foo: "fooValue" to "foo":"fooValue"? Is there a Regular Expression that can make this easy?
Thanks in advance!
This regex will do the trick
$json = preg_replace('/([{,])(\s*)([A-Za-z0-9_\-]+?)\s*:/','$1"$3":',$json);
It's a php though! I assume it's not a problem converting it to JS.
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 have valid JSON), you could instead use ([^'":]+) to mean anything other than double or single quotes or a colon. This would still limit you further than the JSON standard (which allows single quotes in the name) but then you wouldn't be able to parse using this method. You can have all sorts of stuff in here with this expression ([^'":]+), so be careful.
Hope this helps.
edit — came back to point out, first and foremost, that this is not a problem that can be solved with a regular expression.
It's important to distinguish between JSON notation as a serialized form, and JavaScript object constant notation.
This:
{ x: "hello" }
is a perfectly valid JavaScript value (an expression fragment), so that this:
var y = { x: "hello" };
gives you exactly the same result as:
var y = { "x": "hello" };
In other words, the value of "y" in either of those cases will be exactly the same. Completely, exactly the same, such that it would not be possible to ever tell which of those two constants was used to initialize "y".
Now, if what you want to do is translate a string containing JavaScript style "JSON shorthand" without quotes into valid JSON, the only thing to do is parse it and reconstruct the string with quotes around the property names. That is, you will have to either write your own "relaxed" JSON parser than can cope with unquoted identifiers as property names, or else find an off-the-shelf parser that can handle such relaxed syntax.
In your case, it looks like once you have the "relaxed" parser available, you're done; there shouldn't be any need for you to translate back. Thankfully, your "invalid" JSON response is completely interpretable by JavaScript itself, so if you trust the data source (and that's a big "if") you should be able to evaluate it with "eval()".
UPD 2020: the object you have is a valid javascript object, but not 100% valid JSON.
An easy way to convert it to valid JSON is to utilize the features JavaScript provides you with, JSON.stringify:
JSON.stringify(object)
You can run this in your browser's JS console.
To get it formatted (aka "pretty-printed"), you can pass two arguments to this function - the replacer (a function which allows you to filter out some of the properties of your object; just pass a null if you don't care) and space (either the number of spaces or a string which will be placed before each key-value pair of your object' string representation):
JSON.stringify(object, null, 4)
In your case, this call
JSON.stringify({
aNumber: 200,
someText: '\'hello\' world',
anObject: {
'foo': 'fooValue',
'bar': '10.0'
}
}, null, 4)
will give you
{
"aNumber": 200,
"someText": "'hello' world",
"anObject": {
"foo": "fooValue",
"bar": "10.0"
}
}
You **do not** need to do this - you've already got a valid **JSON object**. Read 'bout JSON [here][1].
If you need to get value, you just write `data.whatever` and it just works. E.g.: if you have JSON **object** `data`:
{
moo: "foo",
foo: "bar"
}
All possible fields are `moo` and `foo` and their use are `data.moo` and `data.foo` respectively. And if you want to use `data` as a jQuery argument, you just pass it as-is: `$.load("http://my.site.com/moo", data, function(response){ /* ... */ })`.
**Note:** in the last example i've mentioned, response will be a string. To make it a valid JSON object use `$.parseJSON(response);` method.
Since it's a malformed "JSON", you will not be able to use jQuery.getJSON.
You can use
jQuery.ajax({
url : myUrl,
data : myParams,
type : "GET",
success : function(jsontext)
{
// jsontext is in text format
jsontext = jsontext.replace("'", "\"");
// now convert text to JSON object
var jsonData = eval('(' + jsontext+ ')');
// rest of the code
}
});