I am getting this String as input
"countries" : "[[england, australia], [UAE, China], [UAE]]"
Requirement
I thought that, I need to transform this String into
{"countries": [["england", "australia"], ["UAE", "China"], ["UAE"]]}
Then I can convert it to Object in js using json.parse() method.
I tried various things but none seem to work.
I Tried
JSON.stringify
JSON.parse
eval
I have done this in Java but in Javascript not able to do so.
I am new to js, as in java I can easily do this JSONObject.
Any help will be appreciated, Thanks !!
This requires multiple steps:
Wrap the input in curly braces and do a JSON.parse:
const input = "\"countries\" : \"[[england, australia], [UAE, China], [UAE]]\""
const result = JSON.parse("{" + input + "}")
That gives you an object like:
{
"countries": "[[england, australia], [UAE, China], [UAE]]"
}
Then wrap the inner strings with double quotes and parse it again:
const inner = result.countries
result.countries = JSON.parse(inner.replaceAll(/([a-zA-Z]+)/g, '"$1"'))
That gives you result:
{
"countries": [
[
"england",
"australia"
],
[
"UAE",
"China"
],
[
"UAE"
]
]
}
I am working on an Express app and have an issue trying to match up the values of two arrays
I have a user-entered string which which come through to me from a form (e.g.let analyseStory = req.body.storyText). This string contains line breaks as \r\n\.
An example of string is
In the mens reserve race, Cambridges Goldie were beaten by Oxfords
Isis, their seventh consecutive defeat. \r\n\r\nIn the womens reserve
race, Cambridges Blondie defeated Oxfords Osiris
However before I print this to the browser the string is run through a text analysis library called pos e.g.
const tagger = new pos.Tagger();
res.locals.taggedWords = tagger.tag(analyseStory);
This returns to me an array of words in the string and their grammatical type
[ [ 'In', 'Noun, sing. or mass' ],
[ 'the', 'Determiner' ],
[ 'mens', 'Noun, plural' ],
[ 'reserve', 'Noun, sing. or mass' ],
[ 'race', 'Noun, sing. or mass' ],
[ ',', 'Comma' ],
[ 'Cambridges', 'Noun, plural' ],
[ 'Goldie', 'Proper noun, sing.' ],
[ 'were', 'verb, past tense' ],
[ 'beaten', 'verb, past part' ],
[ 'by', 'Preposition' ],
[ 'Oxfords', 'Noun, plural' ],
....
]
Currently when I print this user-entered text to the screen I loop through the array and print out the key and then wrap that in a class containing the value. This gives a result like:
<span class="noun-sing-or-mass">In</span>
<span class="determiner">the</span>
<span class="noun-plural">mens</span>
so that I can style them.
This all works fine but the problem is that I lose my line breaks in the process. I'm really not sure how to solve this problem but I was thinking that perhaps I could do this on the client side if I break the initial string I get (analyseStory) into an array (where commas, full stops are array items as they are in the above) and then apply the grammatical type supplied in res.locals.taggedWords to the array generated from analyseStory string. However I'm not sure how to do this or even if it is the right solution to the problem.
FWIW if I print analyseStory to the screen without pushng it through text analysis I handle line breaks by wrapping the string in <span style="white-space: pre-line">User entered string</span> rather than converting to <br />.
Any help much appreciated.
This solution uses ES6 Map, and String.replace() with a RegExp to find all words in the analysis, and replace them with a span that has the relevant class name.
You can see in the demo that it preserves the line breaks. Inspect the elements to see the spans with the classes.
const str = 'In the mens reserve race, Cambridges Goldie were beaten by Oxfords Isis, their seventh consecutive defeat. \r\n\r\nIn the womens reserve race, Cambridges Blondie defeated Oxfords Osiris';
const analyzed = [["In","Noun, sing. or mass"],["the","Determiner"],["mens","Noun, plural"],["reserve","Noun, sing. or mass"],["race","Noun, sing. or mass"],[",","Comma"],["Cambridges","Noun, plural"],["Goldie","Proper noun, sing."],["were","verb, past tense"],["beaten","verb, past part"],["by","Preposition"],["Oxfords","Noun, plural"]];
// create Map from the analyzed array. Use Array.map() to change all keys to lower case, and prepare the class name
const analyzedMap = new Map(analyzed.map(([k, v]) =>
[k.toLowerCase(), v.trim().toLowerCase().replace(/\W+/g, '-')]));
// search for a sequence word characters or special characters such as comman and period
const result = str.replace(/(:?\w+|,|.)/gi, (m) => {
// get the class name from the Map
const className = analyzedMap.get(m.toLowerCase());
// if there is a class name return the word/character wrapped with a span
if(className) return `<span class="${className}">${m}</span>`;
// return the word
return m;
});
demo.innerHTML = result;
#demo {
white-space: pre-line;
}
<div id="demo"></div>
<span> is not a block level element. By default it will not line break. You need to either make it block level with css or wrap your text in something that is block level like a <p> tag.
CSS To Make Block
span { display: block; }
You can pre-process text before analyzing text and replace line breaks with some special characters. Something like the following:
const story_with_br = analyseStory.replace(/\n/g, "__br__");
const tagger = new pos.Tagger();
res.locals.taggedWords = tagger.tag(story_with_br);
Hopefully, taggedWords array will contain "__br__" and if it does then while rendering you can add line breaks instead of "__br__"
What you can do is :
Option 1
Edit the library you're using so that it doesn't ignore your \r\n
Option 2
Define a complex key which will define the newlines :
const newlinesKey = 'yourkeyvalue';
Then you replace all newlines by your newlinesKey :
analyseStory.replace(/\r\n/g, newlinesKey);
And after that you can call the text analysis library :
const tagger = new pos.Tagger();
res.locals.taggedWords = tagger.tag(analyseStory);
Like this you would be able to detect when you have to put a new line if the tagger doesn't ignore the keyValue.
What goes wrong if 77>602? I tried in IE, Firefox and Chrome
function getMaxValue(data){
var maxValue=0;
for(var i=0;i<data.length;i++){
if(data[i].value>maxValue){
console.log(data[i].value +">"+maxValue);
maxValue=data[i].value;
}
}
console.log("MaxValue:"+maxValue);
return maxValue;
}
I get my data from a json:
[{
"keyword": "User: Allen-P",
"value": "602"
}, {
"keyword": "From: phillip.allen#enron.com",
"value": "598"
},
{
"keyword": "Date: 2001",
"value": "276"
},
{
"keyword": "Subject: Re:",
"value": "228"
},
{
"keyword": "Date: 2001 Apr",
"value": "77"
},
]
Needed to add some useless description for StackOverflow. Please help me;). The json file is a bit bigger and just an example.
Strings are compared alphabetically even if they contain numbers. The character '7' comes after the character '6', alphabetically, so indeed, in terms of strings, "77" > "602".
The solution is to convert them to numbers first:
if(parseFloat(data[i].value) > maxValue){
Or for sake of brevity, the unary + operator will also do this:
if(+data[i].value > maxValue){
You're currently comparing an integer with a string, which doesn't reliably work in this situation.
Either change your JSON and unquote the values, or use the following code instead:
function getMaxValue(data){
var maxValue=0;
for(var i=0;i<data.length;i++){
if(parseInt(data[i].value) > maxValue) {
console.log(data[i].value +">"+maxValue);
maxValue=data[i].value;
}
}
console.log("MaxValue:"+maxValue);
return maxValue;
}
Also read this for reference.
You need to use parseInt(value,10) to convert the value from a string to a number
What causes this error on the third line?
var products = [{
"name": "Pizza",
"price": "10",
"quantity": "7"
}, {
"name": "Cerveja",
"price": "12",
"quantity": "5"
}, {
"name": "Hamburguer",
"price": "10",
"quantity": "2"
}, {
"name": "Fraldas",
"price": "6",
"quantity": "2"
}];
console.log(products);
var b = JSON.parse(products); //unexpected token o
Open console to view error
products is an object. (creating from an object literal)
JSON.parse() is used to convert a string containing JSON notation into a Javascript object.
Your code turns the object into a string (by calling .toString()) in order to try to parse it as JSON text.
The default .toString() returns "[object Object]", which is not valid JSON; hence the error.
Let's say you know it's valid JSON, but you’re are still getting this...
In that case, it's likely that there are hidden/special characters in the string from whatever source your getting them. When you paste into a validator, they are lost - but in the string they are still there. Those characters, while invisible, will break JSON.parse().
If s is your raw JSON, then clean it up with:
// Preserve newlines, etc. - use valid JSON
s = s.replace(/\\n/g, "\\n")
.replace(/\\'/g, "\\'")
.replace(/\\"/g, '\\"')
.replace(/\\&/g, "\\&")
.replace(/\\r/g, "\\r")
.replace(/\\t/g, "\\t")
.replace(/\\b/g, "\\b")
.replace(/\\f/g, "\\f");
// Remove non-printable and other non-valid JSON characters
s = s.replace(/[\u0000-\u0019]+/g,"");
var o = JSON.parse(s);
It seems you want to stringify the object, not parse. So do this:
JSON.stringify(products);
The reason for the error is that JSON.parse() expects a String value and products is an Array.
Note: I think it attempts json.parse('[object Array]') which complains it didn't expect token o after [.
I found the same issue with JSON.parse(inputString).
In my case, the input string is coming from my server page (return of a page method).
I printed the typeof(inputString) - it was string, but still the error occurs.
I also tried JSON.stringify(inputString), but it did not help.
Later I found this to be an issue with the new line operator [\n], inside a field value.
I did a replace (with some other character, put the new line back after parse) and everything was working fine.
JSON.parse is waiting for a String in parameter. You need to stringify your JSON object to solve the problem.
products = [{"name":"Pizza","price":"10","quantity":"7"}, {"name":"Cerveja","price":"12","quantity":"5"}, {"name":"Hamburguer","price":"10","quantity":"2"}, {"name":"Fraldas","price":"6","quantity":"2"}];
console.log(products);
var b = JSON.parse(JSON.stringify(products)); //solves the problem
You should validate your JSON string here.
A valid JSON string must have double quotes around the keys:
JSON.parse({"u1":1000,"u2":1100}) // will be ok
If there are no quotes, it will cause an error:
JSON.parse({u1:1000,u2:1100})
// error Uncaught SyntaxError: Unexpected token u in JSON at position 2
Using single quotes will also cause an error:
JSON.parse({'u1':1000,'u2':1100})
// error Uncaught SyntaxError: Unexpected token ' in JSON at position 1
products = [{"name":"Pizza","price":"10","quantity":"7"}, {"name":"Cerveja","price":"12","quantity":"5"}, {"name":"Hamburguer","price":"10","quantity":"2"}, {"name":"Fraldas","price":"6","quantity":"2"}];
change to
products = '[{"name":"Pizza","price":"10","quantity":"7"}, {"name":"Cerveja","price":"12","quantity":"5"}, {"name":"Hamburguer","price":"10","quantity":"2"}, {"name":"Fraldas","price":"6","quantity":"2"}]';
If there are leading or trailing spaces, it'll be invalid.
Trailing and leading spaces can be removed as
mystring = mystring.replace(/^\s+|\s+$/g, "");
Source: JavaScript: trim leading or trailing spaces from a string
Here's a function I made based on previous replies: it works on my machine but YMMV.
/**
* #description Converts a string response to an array of objects.
* #param {string} string - The string you want to convert.
* #returns {array} - an array of objects.
*/
function stringToJson(input) {
var result = [];
// Replace leading and trailing [], if present
input = input.replace(/^\[/, '');
input = input.replace(/\]$/, '');
// Change the delimiter to
input = input.replace(/},{/g, '};;;{');
// Preserve newlines, etc. - use valid JSON
//https://stackoverflow.com/questions/14432165/uncaught-syntaxerror-unexpected-token-with-json-parse
input = input.replace(/\\n/g, "\\n")
.replace(/\\'/g, "\\'")
.replace(/\\"/g, '\\"')
.replace(/\\&/g, "\\&")
.replace(/\\r/g, "\\r")
.replace(/\\t/g, "\\t")
.replace(/\\b/g, "\\b")
.replace(/\\f/g, "\\f");
// Remove non-printable and other non-valid JSON characters
input = input.replace(/[\u0000-\u0019]+/g, "");
input = input.split(';;;');
input.forEach(function(element) {
//console.log(JSON.stringify(element));
result.push(JSON.parse(element));
}, this);
return result;
}
One other gotcha that can result in "SyntaxError: Unexpected token" exception when calling JSON.parse() is using any of the following in the string values:
New-line characters.
Tabs (yes, tabs that you can produce with the Tab key!)
Any stand-alone slash \ (but for some reason not /, at least not on Chrome.)
(For a full list see the String section here.)
For instance the following will get you this exception:
{
"msg" : {
"message": "It cannot
contain a new-line",
"description": "Some discription with a tabbed space is also bad",
"value": "It cannot have 3\4 un-escaped"
}
}
So it should be changed to:
{
"msg" : {
"message": "It cannot\ncontain a new-line",
"description": "Some discription with a\t\ttabbed space",
"value": "It cannot have 3\\4 un-escaped"
}
}
Which, I should say, makes it quite unreadable in JSON-only format with larger amount of text.
My issue was that I had commented HTML in a PHP callback function via Ajax that was parsing the comments and return invalid JSON.
Once I removed the commented HTML, all was good and the JSON was parsed without any issues.
When you are using the POST or PUT method, make sure to stringify the body part.
I have documented an example here at
https://gist.github.com/manju16832003/4a92a2be693a8fda7ca84b58b8fa7154
[
{
"name": "Pizza",
"price": "10",
"quantity": "7"
},
{
"name": "Cerveja",
"price": "12",
"quantity": "5"
},
{
"name": "Hamburguer",
"price": "10",
"quantity": "2"
},
{
"name": "Fraldas",
"price": "6",
"quantity": "2"
}
]
Here is your perfect JSON content that you can parse.
The only mistake is you are parsing an already-parsed object, so it's throwing an error. Use this and you will be good to go.
var products = [{
"name": "Pizza",
"price": "10",
"quantity": "7"
}, {
"name": "Cerveja",
"price": "12",
"quantity": "5"
}, {
"name": "Hamburguer",
"price": "10",
"quantity": "2"
}, {
"name": "Fraldas",
"price": "6",
"quantity": "2"
}];
console.log(products[0].name); // Name of item at 0th index
If you want to print the entire JSON content, use JSON.stringify().
products is an array which can be used directly:
var i, j;
for(i=0; i<products.length; i++)
for(j in products[i])
console.log("property name: " + j, "value: " + products[i][j]);
Now apparently \r, \b, \t, \f, etc. aren't the only problematic characters that can give you this error.
Note that some browsers may have additional requirements for the input of JSON.parse.
Run this test code in your browser:
var arr = [];
for(var x=0; x < 0xffff; ++x){
try{
JSON.parse(String.fromCharCode(0x22, x, 0x22));
}catch(e){
arr.push(x);
}
}
console.log(arr);
Testing on Chrome, I see that it doesn't allow JSON.parse(String.fromCharCode(0x22, x, 0x22)); where x is 34, 92, or from 0 to 31.
Characters 34 and 92 are the " and \ characters respectively, and they are usually expected and properly escaped. It's characterss 0 to 31 that would give you problems.
To help with debugging, before you do JSON.parse(input), first verify that the input doesn't contain problematic characters:
function VerifyInput(input){
for(var x=0; x<input.length; ++x){
let c = input.charCodeAt(x);
if(c >= 0 && c <= 31){
throw 'problematic character found at position ' + x;
}
}
}
Oh man, solutions in all previous answers didn't work for me. I had a similar problem just now. I managed to solve it with wrapping with the quote. See the screenshot. Whoo.
Original:
var products = [{
"name": "Pizza",
"price": "10",
"quantity": "7"
}, {
"name": "Cerveja",
"price": "12",
"quantity": "5"
}, {
"name": "Hamburguer",
"price": "10",
"quantity": "2"
}, {
"name": "Fraldas",
"price": "6",
"quantity": "2"
}];
console.log(products);
var b = JSON.parse(products); //unexpected token o
The error you are getting, i.e., "unexpected token o", is because JSON is expected, but an object is obtained while parsing. That "o" is the first letter of word "object".
It can happen for a lot of reasons, but probably for an invalid character, so you can use JSON.stringify(obj); that will turn your object into a JSON, but remember that it is a jQuery expression.
In my case there are the following character problems in my JSON string:
\r
\t
\r\n
\n
:
"
I have replaced them with other characters or symbols, and then reverted back again from coding.
This is now a JavaScript array of objects, not JSON format. To convert it into JSON format, you need to use a function called JSON.stringify().
JSON.stringify(products)
Why do you need JSON.parse? It's already in an array-of-object format.
Better use JSON.stringify as below:
var b = JSON.stringify(products);
The mistake I was doing was passing null (unknowingly) into JSON.parse().
So it threw Unexpected token n in JSON at position 0.
But this happens whenever you pass something which is not a JavaScript Object in JSON.parse().
Use eval. It takes JavaScript expression/code as string and evaluates/executes it.
eval(inputString);
{
"responseHeader": {
"status": 0,
"QTime": 32
},
"response": {
"numFound": 21,
"start": 0,
"docs": [
{
"description": "The matte finish waves on this wedding band contrast with the high polish borders. This sharp and elegant design was finely crafted in Japan.",
"UID_PK": "8252",
},
{
"description": "This elegant ring has an Akoya cultured pearl with a band of bezel-set round diamonds making it perfect for her to wear to work or the night out.",
"UID_PK": "8142",
},
]
},
"highlighting": {
"8252": {
"description": [
" and <em>elegant</em> design was finely crafted in Japan."
]
},
"8142": {
"description": [
"This <em>elegant</em> ring has an Akoya cultured pearl with a band of bezel-set round diamonds making"
]
},
}
}
This is JSON data I got from solr when i set hl=true and hl.fl=description. Here I got docs tag and highlighting tag. I need to parse highlighting tag to highlight "elegant" in description field which is in <em> tag...one more thing is UID_PK's(8252,8142) in <highlighting> are generated dynamically each time. Please suggest how can I do this if I am getting JSON data as
$.getJSON("http://192.168.1.9:8983/solr/db/select/?wt=json&&start=0&rows=20&q="+newquery+"&sort=price asc&hl=true&hl.fl=description&hl.usePhraseHighlighter=true&json.wrf=?", function(newresult){
and parsing it as
$.each(newresult.response.docs, function(i,item){
and
$.each(newresult.highlighting, function(i,hitem){
Assuming the response is always text and only the to be highlighted elements are enclosed in <em> tags and there is only one of them, you could do this:
var highlight = {};
$.each(newresult.highlighting, function(i, hitem){
var match = hitem.description[0].match(/<em>(.*?)<\/em>/);
highlight[i] = match[1];
});
$.each(newresult.response.docs, function(i, item){
var word = highlight[item["UID_PK"]];
var result = item.description.replace(new RegExp(word, 'g'), '<em>' + word + '</em>');
// do something with the result
});
This only works if word does not contain nay special regular expression characters (in which case you'd have to escape them). If you know that the to be highlighted word only occurs once in the search results, you don't have to use regex:
item.description.replace(word, '<em>' + word + '</em>');
DEMO