Parse text to json like using javascript (without jquery) - javascript

I have a text (pure text) that has values aligned to right, and field names (keys) aligned to left.
Key and Values have a single blank space Maximum for each, and any number of spaces separating them - minimum 2 spaces.
I need to get them to a tree so I can read those fields and extract values. I don't know how to proceed and parse this text (Example below) to the json like structure.
Example Text Input:
Item Name 1 value 1
Item Name 2 2
Third Item Long Name val 3
Fourth Item value 4
Desired output:
output = { 'ItemName1' : 'value 1',
'ItemName2' : '2',
'ThirdItemLongName' : 'val 3',
'FourthItem' : 'value 4' }
Edit:
I ended up using #Gueras Arnaud answer, with a small modification, becuase apparently my data has lots of blank spaces at the right.
var source = document.getElementById('source').value;
var newsource = "{" + source.replace(/(.+?)(?:\t+|\s{2,})(.+?)\n/g, '"$1":"$2",').replace(/,$/, '') + '}';
var jsonobjtree = JSON.parse(newsource);
for (var key in jsonobjtree) {
if (jsonobjtree.hasOwnProperty(key)) {
jsonobjtree[key] = jsonobjtree[key].replace(/^\s+|\s+$/g, '')
}
}

The best tool for that is regexp and the use of replace.
In this example, I try to match each line with this pattern :
/(.+?)(?:\t+|\s{2,})(.+?)\n
And insert the result to being like this : "key" : "value",
After I add { and } around the string result.
And to obtain an object I use JSON.parse()
var source = document.getElementById('source').value;
var newsource = "{" + source.replace(/(.+?)(?:\t+|\s{2,})(.+?)\n/g, '"$1":"$2",').replace(/,$/, '') + '}';
var obj = JSON.parse(newsource);
document.getElementById('source').value = newsource;
<textarea id="source" rows="10" cols="100">
Item Name 1 value 1
Item Name 2 2
Third Item Long Name val 3
Fourth Item value 4
</textarea>

Related

Extract certain Columns and Rows from a json string

I get a JSON response like this from a server,
{
id : 1,
text : 'Name City Country \nJohn \n Chicago \nIllinois \nAlbert \nHouston \nTexas '
}
if I do console.log(response.text); the output is like this in tabular form
Now I want only want the Name column along with the rows and the output should look like this
Suggest me a workaround for this. Since the value is a string I'm facing a lot of trouble to extract only the required columns
I haven't tested this, but something like this should work:
var jsonData = "{ id : 1, text : 'Name City Country \nJohn \n Chicago \nIllinois \nAlbert \nHouston \nTexas ' }";
var obj1 = jsonData.split('\n');
for(var i= 1; i<obj1.length-2; i=i+3)
{
console.log("Name: " +obj1[i]+", City: "+obj1[i + 1]+", Country: " +obj1[i + 2]);
}
Use trim and split to get the Name City and Country texts.
const obj = { id : 1, text : 'Name City Country \nJohn \n Chicago \nIllinois \nAlbert \nHouston \nTexas ' }
console.log(obj.text.split("\n")[0].trim().split(" "));
You can use any of the javascript csv parser to parse the text to csv and access the particular column.
Ref: javascript-code-to-parse-csv-data

I am taking user input and splitting it - how to best check types for each and also remove spaces?

i'm not sure if there's a better way to do this.
basically, just taking user inputs for example - hair salon, 1, 4
when I split by , i get ['hair salon',' 1',' 4']. I am doing an error check to make sure its always only 3 values passed max, but how can I remove the spaces (' 4') and also check that 'hair salon' is a string, and the other two are numbers?
Thanks
Suppose you have user input as
hair salon, 1, 4
Now you split(','), you will get an array as
var arr = ['hair salon', '1','4']
You will get every input as string
for(i=0;i<arr.length;i++)
{
arr[i] = arr[i].trim() // will remove space from back & front
}
In case you needed to get the data type of inputs, you can check that using
typeOf (arr[i])) - in the for loop itself
Hope, it suffice your need
Since split() returns string array so all elements will be string . you can convert your second and third parameter with parseInt(). If value cannot be converted to a number it will return NaN:
Try this code:
var str="hair salon, 1, 4"
var val=str.split(', ');
var a=parseInt(val[1]);
var b=parseInt(val[2]);
var c=a+b;
console.log(c);
Consider the following function validateInput to validate user input:
function validateInput(str){
var items = str.split(",").map((v) => v.trim());
if (items.length > 3
|| typeof items[0] !== 'string' || /^[\d-]+$/.test(items[0])
|| isNaN(Number(items[1])) || isNaN(Number(items[2])))
{
if (validateInput.items) validateInput.items = null; // clear previous input items
throw new Error("Invalid data!");
}
validateInput.items = items;
return true;
}
validateInput.items = null; // static property containing valid user input
console.log(validateInput("hair salon, 1, 4")); // true
console.log(validateInput.items); // ["hair salon", "1", "4"]
console.log(validateInput("-8, 7, e")); // will throw "Error: Invalid data!"

Is there any generic function for subscripting?

I have a web page in which contents are loaded dynamically from json. Now i need to find the texts like so2,co2,h2o after the page gets loaded and have to apply subscript for those texts. Is it possible to do this?? If yes please let me know the more efficient way of achieving it.
for example :
var json = { chemA: "value of CO2 is", chemB: "value of H2O is" , chemC: "value in CTUe is"};
in the above json i need to change CO2,H2O and e in CTUe as subscript. how to achieve this??
Take a look at this JSfiddle which shows two approaches:
HTML-based using the <sub> tag
Pure Javascript-based by replacing the matched number with the subscript equivalent in unicode:
http://jsfiddle.net/7gzbjxz3/
var json = { chemA: "CO2", chemB: "H2O" };
var jsonTxt = JSON.stringify(json).replace(/(\d)+/g, function (x){
return String.fromCharCode(8320 + parseInt(x));
});
Option 2 has the advantage of being more portable since you're actually replacing the character. I.e., you can copy and paste the text into say notepad and still see the subscripts there.
The JSFiddle shows both approaches. Not sure why the magic number is 8320 when I was expecting it to be 2080...
So you are generating DOM element as per JSON data you are getting. So before displaying it to DOM you can check if that JSON data contains so2,co2,h2o and if it is then replace that with <sub> tag.
For ex:
var text = 'CO2';
text.replace(/(\d+)/g, "<sub>" + "$1" + "</sub>") ;
And this will returns something like this: "CO2".
As per JSON provided by you:
// Only working for integer right now
var json = { chemA: "value of CO2 is", chemB: "value of H2O is" , chemC: "value in CTUe is"};
$.each(json, function(index, value) {
json[index] = value.replace(/(\d+)/g, "<sub>" + "$1" + "</sub>");
});
console.log(json);
Hope this will helps!
To do this, I would create a prototype function extending String and name it .toSub(). Then, when you create your html from your json, call .toSub() on any value that might contain text that should be in subscript:
// here is the main function
String.prototype.toSub = function() {
var str=this;
var subs = [
['CO2','CO<sub>2</sub>'],
['H2O','H<sub>2O</sub>'],
['CTUe','CO<sub>e</sub>'] // add more here as needed.
];
for(var i=0;i<subs.length;i++){
var chk = subs[i][0];
var rep = subs[i][1];
var pattern = new RegExp('^'+chk+'([ .?!])|( )'+chk+'([ .?!])|( )'+chk+'[ .?!]?$','ig'); // makes a regex like this: /^CO2([ .?!])|( )CO2([ .?!])|( )CO2[ .?!]?$/gi using the surrent sub
// the "empty" capture groups above may seem pointless but they are not
// they allow you to capture the spaces easily so you dont have to deal with them some other way
rep = '$2$4'+rep+'$1$3'; // the $1 etc here are accessing the capture groups from the regex above
str = str.replace(pattern,rep);
}
return str;
};
// below is just for the demo
var json = { chemA: "value of CO2 is", chemB: "value of H2O is" , chemC: "value in CTUe is", chemD: "CO2 is awesome", chemE: "I like H2O!", chemF: "what is H2O?", chemG: "I have H2O. Do you?"};
$.each(json, function(k, v) {
$('#result').append('Key '+k+' = '+v.toSub()+'<br>');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="result"></div>
Note:
Anytime you do something like this with regex, you run the chance of unintentionally matching and converting some unwanted bit of text. However, this approach will have far fewer edge cases than searching and replacing text in your whole document as it is much more targeted.

Extract numeric values with inch notation in a string and return larger one

I am trying to extract size information from products having names like.
Product A 30" Metalic Grey
Product B 31.50" Led 54 watt
Product C 40"-60" Dark Green
My current code to fetch size information is
var product_name = $(this).text();
product_name.split('"')[0].slice(-2);
I am having difficulty to deal sizes with points for example 31.50".
Is there a better way to extract sizes from above example product names also for product names like third product with size range it needs to return the bigger numeric value which is 60.
If you want to get all sizes from a string, you can use the regular expression [\d.]+(?="):
var sizes = text.match(/[\d.]+(?=")/g);
This will return an array of strings, such as ["31.50"] or ["40", "60"].
You can further process the array, e.g. convert the elements to numbers:
sizes = sizes.map(Number); // ["31.50"] -> [31.50]
and/or get the maximum value:
var maxSize = Math.max.apply(null, sizes); // ["40", "60"] -> 60
What about this?
product_name.replace(/^.*?([\d\.]+)"[^"]*$/, '$1');
You'll need to separate at the first " symbol, then find the last space before it:
var product_name = $(this).text();
var size = product_name.split('"')[0];
var space = product_name.lastIndexOf(' ');
size.slice(space, -1);
That'll give you everything from ", then back to the space before it.
Here is an example that will use a regex to find the strings then return the largest, run through each example string:
var t = [
'Product A 30" Metalic Grey',
'Product B 31.50" Led 54 watt',
'Product C 40"-60" Dark Green'
]
var getMaxInches = function(str) {
var inches = str.match(/[0-9]+(\.[0-9]+)?"/g); // The inches format pattern
var maxMeasure = 0;
for(i in inches){
var measure = (inches[i]).slice(0,-1); // remove the trailing "
maxMeasure = Math.max(Number(measure),maxMeasure);
}
return maxMeasure;
}
for(var i in t) alert(getMaxInches(t[i]));

Converting pre to divs

How would you proceed to transform this :
<pre>
key 1 value 1
key 2 value 2
value 2.2
key 3 value 3
value 3.1
value 3.2
value 3.3
key 4 value4.1 value4.5
</pre>
To this :
<div><pre>
key 1 value 1
</pre></div><div><pre>
key 2 value 2
value 2.2
</pre></div><div><pre>
key 3 value 3
value 3.1
value 3.2
value 3.3
</pre></div><div><pre>
key 4 value4.1 value4.5
</pre></div>
Namely : remplacing continuous blank line*s* (could contains space/tabs and multiples linefeed) to </pre></div><div><pre>
I tried :
var txt = $('pre').text();
txt = txt.replace(/(\r\n|\n|\r)/gm, "</pre></div><div><pre>");
$('div#test').append(txt);
Partially work : each line are changed, I loose my blocks.
Are <pre> line break stocked as \r ? \n ? (all OS? all browsers?)
What would be a good regex to do this?
Any other way you would suggest me to proceed with?
parse the text so you get a list of lines of text
trim each line
wrap each line in <div><pre> tags
concatenate the results together
I would do a remove of the prexisting pre element altogether after parsing out the text. So instead of "transforming" it just extract the text and build a different element altogether.
That does it for me. It could be better:
$(document).ready(function(){
var lines = $('pre').html().split(/\n\s*\n/);
$('pre').remove();
for(i = 0; i < lines.length; i++){
if($.trim(lines[i].length) > 0){
var preDiv = $('<pre />');
var keyDiv = $('<div />');
preDiv.append(keyDiv);
keyDiv.html(lines[i]);
$('body').append(preDiv);
}
}
});
It doesnt address any whitespace. You can remove it with trim() in the line keyDiv.html("key" + $.trim(lines[i]))
You can use jQuery's wrap function
$('pre').text($.trim($(this).text()).wrap('<div></div>');

Categories

Resources