I have came across an odd problem with getting JSON data like the following.
[
{
"type":"ripe",
"red":137,
"green":68,
"blue":40,
"strftime(\"%H:%M:%S\", time)":"18:46:37"
},
]
I was not able to compare this data by type using JavaScript, they both successfully went through my if statement for some odd reason. The total count for both variables is equal to 2.
let counterLoop = function() {
for (let i = 0; i < data.length; i++) {
let fruitType = JSON.stringify(data[i].type);
sortFruit(fruitType.toLowerCase());
}
}
let sortFruit = function(fruitType) {
if (fruitType.localeCompare('ripe') === 0){} {
totalRipeFruit++;
$("#totalRipeFruit").text(totalRipeFruit);
}
if (fruitType.localeCompare('unripe') === 0){} {
totalUnripeFruit++;
$("#totalUnripeFruit").text(totalUnripeFruit);
}
}
Any idea why this could be the case?
Thank you very much!
You have two problems here; First of all there is no need for the JSON.stringifyon the type, just leave it out as it will return the string containing useless quotes.
Secondly, your if statements are messed up: You have a second pair of brackets behind each one, so simply change
if (fruitType.localeCompare('ripe') === 0){} {
totalRipeFruit++;
$("#totalRipeFruit").text(totalRipeFruit);
}
if (fruitType.localeCompare('raw') === 0){} {
totalRawFruit++;
$("#totalRawFruit").text(totalRawFruit);
}
To:
if (fruitType.localeCompare('ripe') === 0) {
totalRipeFruit++;
}
if (fruitType.localeCompare('raw') === 0) {
totalRawFruit++;
}
Related
I'm wanting to extract multiple json objects from within a text string, whilst preserving the text either side of the json. The use case for this is to format a log file, which has text statements interspersed with json objects.
An example string for which I may need to perform this on is as follows...
beforetext{"Message":"The request is invalid.","ModelState":{"Id":["Unknown
contract"]}}middletext{"Message":"The request is invalid.","ModelState":
{"Id":["Unknown contract"]}}aftertext
I made some headway by looking for the { and } and with the indexes I was able to extract and slice down the string until I had my json objects and my other text.
The problem is that a json object can have multiple { and } characters, like in the example above, and I can't pinpoint where one object definitively starts and ends.
Once I have the json extracted, and the text between, I'll be looking to display like this..
beforetext
{
"Message": "The request is invalid.",
"ModelState": {
"Id": [
"Unknown contract"
]
}
}
middletext
{
"Message": "The request is invalid.",
"ModelState": {
"Id": [
"Unknown contract"
]
}
}
aftertext
I've looked into regex but I've not been able to find a clear solution.
Any ideas?
It's not too hard to parse this yourself so long as you can reasonably predict the kind of string you will be dealing with. You can keep a stack of your delimiters and when the stack arrives at or departs a length of zero, you know you are at a boundary. You can suck strings in as whole units to allow them to contain anything (except ").
This will assume the strings and containers are balanced, but it's not hard to add basic error checking to this kind of parser. I changed your data to add a few more difficulties (like starting with [ and including {} in strings)
let s = 'beforetext[{"Message":"The request is {invalid.}"},{"ModelState":{"Id":["Unknown contract"]}}]middletext{"Message":"The request is invalid.","ModelState": {"Id":["Unknown contract"]}}aftertext'
function balance(s){
let opens = ['{', '['], closes = ['}', ']'], // define opening and closing delimiters
res = [], current = '', stack = []
for (let i = 0; i<s.length; i++){
let char = s[i]
if (char == '"'){ // take strings as units to allow them to contain delimters
let next = s.indexOf('"', i+1)
current += s.substring(i, next+1)
i = next
}
else if(opens.includes(char)) { // new opening, push to stack
if (stack.length == 0){
res.push(current)
current = char
}
stack.push(char)
} else if (closes.includes(char)) { // new closing pop
stack.pop()
if (stack.length == 0) {
res.push(current + char)
current = ''
}
}
else {current += char}
}
res.push(current)
return res
}
console.log(balance(s).join('\n\n'))
I managed to solve this by implementing the suggestion by Andrew Rueckert
I iterated through every character in the string.
If I encountered an '{' I incremented the depth by 1. If it's a '}' I decremented the depth by 1.
Whenever the depth was at 0, I knew these were my start and end indexes for the json.
I stored the text up to the start index, and the json as an object. I then pushed these properties onto an array.
Some additional logic to account for the end of a string where there is text remaining but no json, and if the string doesn't contain any '{' or '}'.
Example...
jsonObjects()
{
var jsonString = this.value;
var jsonObjects = [];
var remainingString = '';
var depth = 0;
var indexStart = 0;
var indexEnd = 0;
var pointer = 0;
if (!jsonString.includes('{') && !jsonString.includes('}')) {
jsonObjects.push({ "pretext": jsonString, "json": null });
}
else {
for (var i = 0; i < jsonString.length; i++)
{
if (jsonString.charAt(i) === '{') {
if (depth === 0) {
indexStart = i;
}
depth++;
}
else if (jsonString.charAt(i) === '}') {
depth--;
if (depth === 0) {
indexEnd = i;
var finalJson = JSON.parse(jsonString.substring(indexStart, indexEnd + 1));
var gapText = jsonString.substring(pointer, indexStart);
jsonObjects.push({ "pretext": gapText, "json": finalJson });
pointer = indexEnd + 1;
remainingString = jsonString.substring(pointer, jsonString.length);
if (!remainingString.includes('{') && !remainingString.includes('}')) {
jsonObjects.push({ "pretext": remainingString, "json": null });
}
}
}
}
}
return jsonObjects;
}
With some conditional formatting in vue the result looks quite nice..
<div v-for="jsonObject in jsonObjects" v-bind:key="jsonObject.pretext">
<p>{{ jsonObject.pretext }}</p>
<vue-json-pretty :deep="1" v-if="jsonObject.json != null" :data="jsonObject.json"></vue-json-pretty>
</div>
I am not sure if you want all three as group but if not you can split as below. This will give you array with all json objects.
let yourString = 'beforetext{"Message":"The request is invalid.","ModelState":{"Id":["Unknown contract"]}}middletext{"Message":"The request is invalid.","ModelState": {"Id":["Unknown contract"]}}aftertext'
yourString.split(/beforetext\b|middletext\b|aftertext\b/).filter(json=>json)
I'm stuck in nested loops.
this.isRyt is a variable where a retrived string from JSON is stored.
i is a user input variable of type string.
this.storeArray[] is an array where every input of i from user will be stored only if it matches the string stored in this.isRyt variable.So basically I want to compare the strings stored in this.storeArray[] by using index k to the string stored in this.isRryt(as multiple i inputs from user will stored at different index locations in this.storeArray[]),and if the string is not matched then there is variable counter which will get incremented.incCounter is nothing but a simple counter variable initialized with value 0.
My try: I tried using the below loop , but this.counter++ get incremented multiple times in a single time(multiple iterations of k) as it is inside the for loop. I want to make it increment only a single time but the for condition should not be omitted.
filterAnswer(i:any) //Comparing Answer submitted by user with JSON answer
{
this.isRyt = this.questArrayNew1[0].isRight;
if(this.isRyt == i )
{
for(let k = 0 ; k < this.questArray.length ; k++)
{
if(this.storeArray[k] == i)
{
console.log(k);
}
else
{
this.counter++; //WANT TO INCREMENT ONLY ONE TIME IF IT DOESNT SATISFY THE CONDITION FOR WHOLE K=0,1,2,3.. variable
}
}
this.storeArray[this.incCounter] = i ;
console.log(this.storeArray);
this.incCounter++;
}
else
{
return 0;
}
}
If I am understanding you correctly, this.counter only needs to be incremented once. You could try something like this:
filterAnswer(i:any) //Comparing Answer submitted by user with JSON answer
{
var notCounted = true; //condition for this.counter++ code block to be executed
this.isRyt = this.questArrayNew1[0].isRight;
if(this.isRyt == i )
{
for(let k = 0 ; k < this.questArray.length ; k++)
{
if(this.storeArray[k] == i)
{
console.log(k);
}
else
{
while(notCounted)
{ //executes while bool is true
this.counter++;
notCounted = false; //incremented so now no longer needed
}
}
}
this.storeArray[this.incCounter] = i ;
console.log(this.storeArray);
this.incCounter++;
}
else
{
return 0;
}
}
I am currently working on a challenge to convert any amount of arbitrary numbers entered into the function below as a currency (expressed by a string where every three characters are separated by a comma). All was okay until I realized that if the length of the number entered was 4, then the comma would need to be placed as 1,234 rather than 123,4.
It seems the function has spiralled out of control a little when I wrapped the initial if statement around my for loop. (1) I keep getting thrown an 'Uncaught SyntaxError: Unexpected token else' in the console. (2) I thought it may be due trying to place an if/else around the for/if/else. Any light shed on my error would be much appreciated. Charlie
function toCurrency(price){
var newStrng = price.toString().split("");
var stringCh = [];
if(newStrng.length===4){
console.log("gotcha");
stringCh = newStrng.splice(1,0,",");
return stringCh;
} else {
for(var i = 0; i < newStrng.length; i++) {
if(i %3 === 0 && i !== 0){
stringCh.push(",");
stringCh.push(newStrng[i]);
}
} else {
stringCh.push(newStrng[i]);
}
}
var finallyDone = stringCh.join("");
return finallyDone;
}//EO function
The if statement in the following block
for(var i = 0; i < newStrng.length; i++) {
if(i %3 === 0 && i !== 0){
stringCh.push(",");
stringCh.push(newStrng[i]);
}
} else {
stringCh.push(newStrng[i]);
}
}
has an extra }, right before the else. Take it out and you should no long receive the syntax error.
You can make it easier to spot mistakes like this in the future by ensuring your code is properly indented so you can see which brackets are associated with which blocks. Though I appreciate it could be reasonably indented in the source code and may not have copied across to SO perfectly.
There is a } in the wrong place inside the for loop, that need to be moved after the else block. As it is, the if statement is located in the for loop, but the else block is located outside of the loop, which is not valid syntax.
function toCurrency(price){
var newStrng = price.toString().split("");
var stringCh = [];
if(newStrng.length===4){
console.log("gotcha");
stringCh = newStrng.splice(1,0,",");
return stringCh;
} else {
for(var i = 0; i < newStrng.length; i++) {
if(i %3 === 0 && i !== 0){
stringCh.push(",");
stringCh.push(newStrng[i]);
} else {
stringCh.push(newStrng[i]);
}
}
}
var finallyDone = stringCh.join("");
return finallyDone;
}//EO function
remove } after,
stringCh.push(newStrng[i]);
How i can get value of TobaccoProduct_0 , TobaccoProduct_1, TobaccoProduct_2.
Currently i am trying with this code and its not working
for (var count = 0; count < $scope.ProductCount; count++) {
if ($scope.TobaccoProduct_[count] == true) {
$("#SmokeReview").submit();
} else {
alert("plz chcek atleast one value");
}
}
for (var count = 0 ; count < $scope.ProductCount; count++) {
if ($scope["TobaccoProduct_"+count] == true) {
$("#SmokeReview").submit();
}
else {
alert("plz chcek atleast one value");
}
}
You really shouldn't be doing it this way though. You should surely be using some kind of array to store the Tobacco products rather than numbering the variable name.
Edit: You might actually be doing it that way (otherwise you'd have a really strange ProductCount implementation) and so the above solution won't work, you'll have to use $scope.TobaccoProduct[count]
I have a string like this being returned from my backend:
"1,2,3,4,5,6"
I have a large array locally and want to display only those items not in this list, so I was thinking of exploding this string into an array but how can I search efficiently? As far as I know there are no hashmaps in JS so how does one do this? I just need to check for key existence.
All Javascript objects are also hash tables that can store string or numeric keys:
var x = {};
x["foo"] = 1;
if("foo" in x) { alert("hello!"); }
if("bar" in x) { alert("should never see this"); }
"1,2,3,4,5,6".split(",").some(function(letter) {
return letter === '2'
});
Warning: Might not work in IE (or other crappy browser)
Cross browser version (that relies on native code for performance):
var arr = "1,2,3,4,5,6".split(",");
if(arr.some)
{
arr.some(function(letter) {
return letter === '2'
});
}
else
{
for(var i = 0 ; i < arr.length ; i++ )
{
if(arr[i] === '2') return true;
}
}