Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I have a string like
"Something has happened {\"prop1\":{\"name\":\"foo\"}}"
and I would like to parse out the JSON so that I can format the string. Such as:
Something has happened
{
"prop1":{
"name":"foo"
}
}
In JavaScript, what would be a good way to accomplish this.
There can be multiple object in the string and also the object will not be known it could contain many nested objects or arrays. Thanks in advance.
The minimum would be simply pretty-printing the string
OK then. Well a really simple, non-optimised, not-necessarily robust pretty print function might look something like this:
function basicPrettyPrint(str) {
var output = '';
var indentLevel = 0;
var indent = ' ';
var inQuotes = false;
for (var i = 0; i < str.length; i++) {
var current = str[i];
if (current === '"' && indentLevel > 0) {
inQuotes = !inQuotes;
output += current;
} else if (inQuotes) {
output += current;
} else if (current === ',' && indentLevel > 0) {
output += ',\n' + indent.repeat(indentLevel);
} else if (current === '{' || current === '[') {
if (indentLevel === 0) output += '\n';
output += current + '\n' + indent.repeat(++indentLevel);
} else if (current === '}' || current === ']') {
output += '\n' + indent.repeat(--indentLevel) + current;
if (indentLevel === 0) output += '\n';
} else {
output += current;
}
if (indentLevel < 0) {
// parse failure: unbalanced brackets. Do something.
}
}
return output;
}
var input = 'Here is a "simple" object, for testing: {"prop1":{"name":"foo"}}And here is a more complicated one that has curly brackets within one of the property values:{"prop1":"{this is data, not an object}","arr":[1,{"a":"1","b":{"x":1,"y":[3,2,1]}},3,4]}And a non-nested array:[1,2,3]';
console.log(basicPrettyPrint(input));
The above doesn't allow for escaped quotation marks within properties, and probably a bunch of other things I didn't think of for purposes of a quick demo, but I leave those things as exercises for the reader...
P.S. The string .repeat() method might need to be polyfilled.
Can we assume that the '{' and '}' indicate the start and end of the json. If so, you can get a substring; see code below. You could do the same thing with regular expressions.
var str = "Something has happened {\"prop1\":{\"name\":\"foo\"}}"
var start = str.indexOf("{");
var end = str.lastIndexOf("}");
var json = str.substr(start, end);
Related
This question already has answers here:
Remove consecutive duplicate characters in a string javascript
(5 answers)
Closed 1 year ago.
I have seen a few examples of this, but they're either not in JS or are terribly inefficient (like the solution I have now). Basically what I want done is a function that takes in a string and removes any characters that are adjacent and the same. As an example, "jjjavvvaaassscript" would become "javascript". What I'm not looking for is where it would become "javscript" (eliminating the second "a"). I do have a working function shown below, but it's absolutely horrendous and I'm looking for a better way to do it.
function removeChar(text, index) {
return(text.slice(0,index)+text.slice(index+1));
}
function removeDuplicates(text) {
var prevChar = "";
var finalT = text;
var i = 0;
for(i = 0; i < text.length; i++) {
if(finalT.charAt(i) == prevChar) {
if(i > finalT.length) {
return finalT;
} else {
finalT = removeChar(finalT, i);
i--;
}
} else {
prevChar = finalT.charAt(i);
}
}
return finalT;
}
Any help would be greatly appreciated!
I'd use a regular expression to match a character, then backreference it as many times as possible (so, for example, it'll match jjj, or a, or vvv, etc), and then replace with the one character:
const removeDuplicates = str => str.replace(/(.)\1*/g, '$1');
console.log(removeDuplicates('jjjavvvaaassscript'));
If you had to iterate more manually, similar to your current method, then:
const removeDuplicates = str => {
let lastChar = str[0];
let finalT = str[0];
for (const char of str.slice(1)) {
if (lastChar !== char) finalT += char;
lastChar = char;
}
return finalT;
};
console.log(removeDuplicates('jjjavvvaaassscript'));
This question already has answers here:
Repeat String - Javascript [duplicate]
(30 answers)
Closed 7 years ago.
I need to understand how Javascript handles the new string object just like in the C# code below
var UpperBound = 14;
for (int i = 0; i < UpperBound; i++) {
Console.WriteLine(new string('*', i));
}
Console.ReadLine();
This was how i did it in Javascript:
var upperBound = 14;
for(var i=0;i<upperBound;i++){
console.log(new string("*", i));
}
Am a newbie in programming and i started off with javascript so if i appear dumb by asking this question pls pardon and assist me by explaining.. thanks
There is no equivalent for new string("*", i) in JS. You need to do repetition yourself.
A handy hack is Array(i + 1).join("*"), but it is not very efficient I don't think, as it needs to construct the array. The best way is probably to loop and concatenate.
Your code is good except for this part:
new string("*", i)
It is incorrect syntax for JS. You need to create string another way.
That's how you should create a string with repeating character in JavaScript.
I should note that String.prototype.repeat is a part of ECMAScript 6.
var upperBound = 14;
for(var i=0;i<upperBound;i++)
{
document.write('*'.repeat(i));
document.write("<br/>");
}
Before it, you should use another approach like making this string manually in a for-loop like this:
function repeatString(ch, t)
{
var res = '';
for (var i = 0; i < t; i++) res += ch;
return res;
}
var upperBound = 14;
for(var i=0;i<upperBound;i++)
{
document.write(repeatString('*', i));
document.write("<br/>");
}
There are some other approaches and hacks. You can read this StackOverflow topic on it.
I suggest you to read a good tutorial on JavaScript before trying to write it.
C# and JavaScript are very different languages in all terms. You cannot just take a C# code, change a syntax and think that it will work.
I would like to combine two solutions, so (the best option is to use es6-shim) here is a polyfill (borrowed from here)
if (!String.prototype.repeat) {
String.prototype.repeat = function(count) {
'use strict';
if (this == null) {
throw new TypeError('can\'t convert ' + this + ' to object');
}
var str = '' + this;
count = +count;
if (count != count) {
count = 0;
}
if (count < 0) {
throw new RangeError('repeat count must be non-negative');
}
if (count == Infinity) {
throw new RangeError('repeat count must be less than infinity');
}
count = Math.floor(count);
if (str.length == 0 || count == 0) {
return '';
}
// Ensuring count is a 31-bit integer allows us to heavily optimize the
// main part. But anyway, most current (August 2014) browsers can't handle
// strings 1 << 28 chars or longer, so:
if (str.length * count >= 1 << 28) {
throw new RangeError('repeat count must not overflow maximum string size');
}
var rpt = '';
for (;;) {
if ((count & 1) == 1) {
rpt += str;
}
count >>>= 1;
if (count == 0) {
break;
}
str += str;
}
return rpt;
}
}
And the usage:
var upperBound = 14;
for(var i=0;i<upperBound;i++){
console.log("*".repeat(i));
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
i have problem regarding how to compare string in an array..
in my list have jack,john,nami#domain,nami
function **alreadyInList**(list, toBeAdded) {
// return true or false
var delims = "(,)";
var tokens = list.split(delims);
for ( var i = 0; i < tokens.length; i++){
if (tokens[i] === toBeAdded ){
return true;
}
else
return false;
}
}
function addListTo(selectbox, textbox) {
var values = new Array();
var c = 0;
for ( i = 0; i < selectbox.options.length; i++) {
if (selectbox.options[i].selected) {
if (!**alreadyInList**(textbox.value,selectbox.options[i].value)) {
values[c++] = selectbox.options[i].value;
}
}
}
if (values.length == 0) return;
var v = values[0];
for (i = 1; i < values.length; i++) {
v += ',' + values[i];
}
if (textbox.value.length>0) {
if (textbox.value=='Any') {
textbox.value = v;
} else {
textbox.value += ',';
textbox.value += v;
}
} else {
textbox.value += v;
}
}
when i put my condition and i want to add the string into textbox it only work for the first string lets say i put nami as my string then when i want to put nami again it cannot so it works..but after "," i put name#domain .i can put back nami..means i dont want to repetitive string inside my textbox.can someone help me.sorry im still new in this programming..sorry for my english
Here is a revised version of your function to check if a name appears twice in any string in the array
function alreadyInList(list, toBeAdded) {
// return true or false
var delims = ",",
tokens = list.split(delims),
found = false;
var end = tokens.forEach(function (value) {
if (value.indexOf(toBeAdded) !== -1 && found == false) {
found = true;
alert('It\'s been found!');
// Do something
return true;
}
return false;
});
if (found != true) {
alert('Not in the list');
return false;
} else {
return false;
}
}
alreadyInList('marry,joe,gerry', 'marry');
JSFiddle Demo
Additionally if its just one occurance in the list you need something simple without a function.
var str = "marry,joe,gerry",
key = "marry";
if ( str.indexOf(key) !== -1 ) {
// Its found! Do something
}
As Sasquatch pointed out above, the issue is the delimiter you are using for split. You want to split by a single comma ',' -- not by the three characters '(,)'.
The way your code is written, tokens only ever has a single value because the split delimiter is wrong. It is matching the entire string variable list to your toBeAdded string and returning false.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
How do I split a string like this
"please help me "
so that I get an array like this:
["please ","help ","me "]
In other words,I get an array which preserves the space (or spaces)
Thanks
something like :
var str = "please help me ";
var split = str.split(/(\S+\s+)/).filter(function(n) {return n});
FIDDLE
this is tricky without using a function;
var temp = "", outputArray = [], text = "please help me ".split("");
for(i=0; i < text.length; i++) {
console.log(typeof text[i+1])
if(text[i] === " " && (text[i+1] !== " " || typeof text[i+1] === "undefined")) {
outputArray.push(temp+=text[i]);
temp="";
} else {
temp+=text[i];
}
}
console.log(outputArray);
I don't think a simple regex can help this out.
you can use prototype to use it like a native code...
String.prototype.splitPreserve = function(seperator) {
var temp = "",
outputArray = [],
text = this.split("");
for(i=0; i < text.length; i++) {
console.log(typeof text[i+1])
if(text[i] === seperator && (text[i+1] !== seperator || typeof text[i+1] === "undefined")) {
outputArray.push(temp+=text[i]);
temp="";
} else {
temp+=text[i];
}
}
return outputArray;
}
console.log("please help me ".splitPreserve(" "));
I'm wondering if there's a way to count the words inside a div for example. Say we have a div like so:
<div id="content">
hello how are you?
</div>
Then have the JS function return an integer of 4.
Is this possible? I have done this with form elements but can't seem to do it for non-form ones.
Any ideas?
g
If you know that the DIV is only going to have text in it, you can KISS:
var count = document.getElementById('content').innerHTML.split(' ').length;
If the div can have HTML tags in it, you're going to have to traverse its children looking for text nodes:
function get_text(el) {
ret = "";
var length = el.childNodes.length;
for(var i = 0; i < length; i++) {
var node = el.childNodes[i];
if(node.nodeType != 8) {
ret += node.nodeType != 1 ? node.nodeValue : get_text(node);
}
}
return ret;
}
var words = get_text(document.getElementById('content'));
var count = words.split(' ').length;
This is the same logic that the jQuery library uses to achieve the effect of its text() function. jQuery is a pretty awesome library that in this case is not necessary. However, if you find yourself doing a lot of DOM manipulation or AJAX then you might want to check it out.
EDIT:
As noted by Gumbo in the comments, the way we are splitting the strings above would count two consecutive spaces as a word. If you expect that sort of thing (and even if you don't) it's probably best to avoid it by splitting on a regular expression instead of on a simple space character. Keeping that in mind, instead of doing the above split, you should do something like this:
var count = words.split(/\s+/).length;
The only difference being on what we're passing to the split function.
Paolo Bergantino's second solution is incorrect for empty strings or strings that begin or end with whitespaces. Here's the fix:
var count = !s ? 0 : (s.split(/^\s+$/).length === 2 ? 0 : 2 +
s.split(/\s+/).length - s.split(/^\s+/).length - s.split(/\s+$/).length);
Explanation: If the string is empty, there are zero words; If the string has only whitespaces, there are zero words; Else, count the number of whitespace groups without the ones from the beginning and the end of the string.
string_var.match(/[^\s]+/g).length
seems like it's a better method than
string_var.split(/\s+/).length
At least it won't count "word " as 2 words -- ['word'] rather than ['word', '']. And it doesn't really require any funny add-on logic.
Or just use Countable.js to do the hard job ;)
document.deepText= function(hoo){
var A= [];
if(hoo){
hoo= hoo.firstChild;
while(hoo!= null){
if(hoo.nodeType== 3){
A[A.length]= hoo.data;
}
else A= A.concat(arguments.callee(hoo));
hoo= hoo.nextSibling;
}
}
return A;
}
I'd be fairly strict about what a word is-
function countwords(hoo){
var text= document.deepText(hoo).join(' ');
return text.match(/[A-Za-z\'\-]+/g).length;
}
alert(countwords(document.body))
Or you can do this:
function CountWords (this_field, show_word_count, show_char_count) {
if (show_word_count == null) {
show_word_count = true;
}
if (show_char_count == null) {
show_char_count = false;
}
var char_count = this_field.value.length;
var fullStr = this_field.value + " ";
var initial_whitespace_rExp = /^[^A-Za-z0-9]+/gi;
var left_trimmedStr = fullStr.replace(initial_whitespace_rExp, "");
var non_alphanumerics_rExp = rExp = /[^A-Za-z0-9]+/gi;
var cleanedStr = left_trimmedStr.replace(non_alphanumerics_rExp, " ");
var splitString = cleanedStr.split(" ");
var word_count = splitString.length -1;
if (fullStr.length <2) {
word_count = 0;
}
if (word_count == 1) {
wordOrWords = " word";
} else {
wordOrWords = " words";
}
if (char_count == 1) {
charOrChars = " character";
} else {
charOrChars = " characters";
}
if (show_word_count & show_char_count) {
alert ("Word Count:\n" + " " + word_count + wordOrWords + "\n" + " " + char_count + charOrChars);
} else {
if (show_word_count) {
alert ("Word Count: " + word_count + wordOrWords);
} else {
if (show_char_count) {
alert ("Character Count: " + char_count + charOrChars);
}
}
}
return word_count;
}
The get_text function in Paolo Bergantino's answer didn't work properly for me when two child nodes have no space between them. eg <h1>heading</h1><p>paragraph</p> would be returned as headingparagraph (notice lack of space between the words). So prepending a space to the nodeValue fixes this. But it introduces a space at the front of the text but I found a word count function that trims it off (plus it uses several regexps to ensure it counts words only). Word count and edited get_text functions below:
function get_text(el) {
ret = "";
var length = el.childNodes.length;
for(var i = 0; i < length; i++) {
var node = el.childNodes[i];
if(node.nodeType != 8) {
ret += node.nodeType != 1 ? ' '+node.nodeValue : get_text(node);
}
}
return ret;
}
function wordCount(fullStr) {
if (fullStr.length == 0) {
return 0;
} else {
fullStr = fullStr.replace(/\r+/g, " ");
fullStr = fullStr.replace(/\n+/g, " ");
fullStr = fullStr.replace(/[^A-Za-z0-9 ]+/gi, "");
fullStr = fullStr.replace(/^\s+/, "");
fullStr = fullStr.replace(/\s+$/, "");
fullStr = fullStr.replace(/\s+/gi, " ");
var splitString = fullStr.split(" ");
return splitString.length;
}
}
EDIT
kennebec's word counter is really good. But the one I've found includes a number as a word which is what I needed. Still, that's easy to add to kennebec's. But kennebec's text retrieval function will have the same problem.
This should account for preceding & trailing whitespaces
const wordCount = document.querySelector('#content').innerText.trim().split(/\s+/).length;
string_var.match(/[^\s]+/g).length - 1;