Splitting a string for CSV formatting - javascript

I have a string that I've formed based on certain data. It contains a list of comma separated values.
I run this string through a function which allows me to separate these values so that I can show them appropriately in the HTML.
This works fine. However there's one error I'm unable to resolve. One of the returned values is from a HTML textfield which means the user can write on multiple different lines. As a result, the function I use to split up my values is splitting up the textfield values into multiple lines.
I've consoled logged my string before it hits the function. As you can see, the comments appear fine in the quotations with a space in between.
20,Order,Item,Title,,Assignee,Comments,Image Path,Timestamp,Due Date,Completed
21,0,1,"Issue 1",,"","I have some comments that are
going here on multiple lines",,"2019/11/28, 12:20:55","",""
The function
csvToJSON(csv) {
const lines: string[] = csv
// escape everything inside quotes to NOT remove the comma there
.replace(/"(.*?)"/gm, (item) => encodeURIComponent(item))
.split('\n');
lines.pop();
// separate the headers from the other lines and split them
const headers: string[] = lines.shift().split(',');
// should contain all CSV lines parsed for the html table
const data: any[] = lines.map((lineString, index) => {
const lineObj = {};
const lineValues = lineString.split(',');
headers.forEach((valueName, index) => {
// remove trailing spaces and quotes
if (lineValues[index] != undefined) {
lineObj[valueName] = lineValues[index].replace(/%22(.*?)%22/gm, (item) => decodeURIComponent(item)).trim();
}
});
return lineObj; // return lineObj for objects.
});
console.log('csvToJSON - data = ', data);
return { data, headers };
}
In the above function, you can see a console log at the end to log the final converted data.
This ends up resulting in the following:
0: {20: "21", Order: "0", Item: "1", Title: ""Issue 1"", "": "", Assignee: """", …}
1: {20: ""}
2: {20: "going here on multiple lines",,"2019/11/28", Order: "12:20:55","","""}
As you can see, my comments have been a bit butchered.
Is there a way to resolve this so that everything else is separated correctly, but my comments text (which can have multiple lines) isn't broken up?

try this method
function CSVtoArray(text) {
var re_valid = /^\s*(?:'[^'\\]*(?:\\[\S\s][^'\\]*)*'|"[^"\\]*(?:\\[\S\s][^"\\]*)*"|[^,'"\s\\]*(?:\s+[^,'"\s\\]+)*)\s*(?:,\s*(?:'[^'\\]*(?:\\[\S\s][^'\\]*)*'|"[^"\\]*(?:\\[\S\s][^"\\]*)*"|[^,'"\s\\]*(?:\s+[^,'"\s\\]+)*)\s*)*$/;
var re_value = /(?!\s*$)\s*(?:'([^'\\]*(?:\\[\S\s][^'\\]*)*)'|"([^"\\]*(?:\\[\S\s][^"\\]*)*)"|([^,'"\s\\]*(?:\s+[^,'"\s\\]+)*))\s*(?:,|$)/g;
if (!re_valid.test(text)) return null;
var a = [];
text.replace(re_value,
function(m0, m1, m2, m3) {
if (m1 !== undefined) a.push(m1.split("|");
else if (m2 !== undefined) a.push(m2.split(","));
else if (m3 !== undefined) a.push(m3);
return '';
});
if (/,\s*$/.test(text)) a.push('');
return a;
};

Related

Remove last comma from JSON file in JS for consuption by Vue app

I'm consuming a JSON file using Axios in my Vue app. One of the fields (country)has a trailing comma and it's causing issues.
JSON
"country": "spain,france,"
....
"country": "spain,belgium,"
...
JS
I tried to replace a word using the code below and this worked fine. It replaced 'france' with 'XXXXXX'
const arr = this.countries;
const newArr = arr.map((countries) => {
if (countries === "france") {
return "XXXXXX";
}
// return countries;
});
console.log("commas " + newArr);
I have tried various ways to remove the end comma but I can't seem to work how to. Can anyone help with this, please?
From this point, where you have the "country" value from your XML for e.g. in the variable countryString you could do following:
let countryString = "belgium,france,";
let countries = countryString.split(",").filter(e => e).map((e) => {
if (e === "france") { return "XXXXXX"; }
return e;
});
console.log(countries);
You can use slice to remove last char:
let countryString = "belgium,france,";
countryString = countryString.slice(0, -1);
console.log(countryString)

How can I add superscripts and subscript in a string?

I have an array of objects containing lots of data or objects which I import and display in a webpage.
const arr = [
{
question: "What is molecular formula for water?",
options: ["H2O","CO2","H2O","H2O"]
}
]
So Is it possible to write superscript and subscript in a string? To make the numbers superscipted or subscripted while displaying in a webpage.
Note: I have array of around 1000 objects from which only 100 of them are displayed. Some of them may contain superscript whereas some of them may not. Isn't there any simpler way like using alt codes for super scripts and subscripts so that I can directly put it in string.
You could map your array of options to a formatted version of that option by using .replace() to wrap each number in <sup></sup> tags to make it appear as subscript text like so:
const arr = [
{
question: "What is molecular formula for water?",
options: ["H2O","CO2","H2O","H2O"]
}
]
const formatted = arr[0].options.map(elem => elem.replace(/(\d)/g, `<sub>$1</sub>`));
console.log(formatted);
document.body.innerHTML = formatted;
Regex free approach. Supports hydrated salts (like blue vitorl) and balancing numbers. To add hydrated salts, just add a dot
const arr = [{
question: "What is molecular formula for water?",
options: ["H2O", "CO2", "H2O", "H2O"]
},
{
question: "What is the molecular formula for Copper(II) sulphate?",
options: ["H2O", "(CuSO4).5H2O", "H2O2", "D2O"]
}
]
arr.forEach(obj => { // map the first array
let answer = obj["options"].map((options) => { // map all the answers
let op = options.split('').map((data, i) => { // split all the answer strings
if (!isNaN(data)) { // if the data is a number the add <sub> tags to it
if (options.split('')[i - 1] != "." && i != 0) { // if i = 0 is a number then it is a blancing number. Then don't add <sub> tags to it
// also check if the previous string is a dot. Means that has water of crystillization or any other extension
let str = "<sub>" + data + "</sub>"
return str
}else{
return data
}
} else {
return data // else return the string
}
})
return op.join("") // join the string
})
// logic to add data display it
let question = document.createElement("h1") // question
question.innerHTML = obj["question"] // append question content
document.body.appendChild(question) // append the question element to body
let ul = document.createElement("ul") // create unsorted list
answer.forEach((things) => { // for each of the answers
let ali = document.createElement("li") // create a li
ali.innerHTML = things // add answers to the lu
ul.appendChild(ali) // append the li to the ul
})
document.body.appendChild(ul) // append the ul to the body
})
We are just splitting your answers and checking if the data is a number. If it is then we add <sub> tags to it.
To display them, we create elements dynamically and in a loop, we add compounds to a li and then append that to a ul
Make sure to follow the basic chem rules while formatting compounds
Generic example for replacing digits in all values with unicode subscript digits :
var json = JSON.stringify( [ { question: "What is molecular formula for water?", options: ["H2O","CO2","H2O","H2O"] } ] )
var arr = JSON.parse(json, (k, v) => v.trim ? v.replace(/\d/, m => '₀₁₂₃₄₅₆₇₈₉'[m]) : v)
console.log(arr)
document.body.textContent = arr[0].options

csv to json, json key are incorrect

I have the following function
generateArrayFromCSV(data, delimiter = ',') {
const titles = data.slice(0, data.indexOf('\n')).split(delimiter);
return data
.slice(data.indexOf('\n') + 1)
.split('\n')
.map(v => {
const values = v.split(delimiter);
return titles.reduce(
(obj, title, index) => ((obj[title] = values[index]), obj),
{}
);
});
};
I input the following code (you need to JSON PARSE this )
generateArrayFromCSV(`"id","longitude","latitude","height","heading","pitch","roll"
"e33ccb1d-bd23-4da7-a006-caa3b998b5a0",139.60705614794117,35.713942413120606,20,0,0,0
"40ddec13-4888-48be-8382-6761b826f2f2",139.60697489329232,35.71356021532803,20,0,0,0
"396c841c-99a2-49ea-928f-dd26'`)
Now, it looks ok, when I load a csv into it, and get the returned value in the console, it looks correct.
The problem is, even if in the console my object appear like this
{"id": ""e33ccb1d-bd23-4da7-a006-caa3b998b5a0"", "longitude": "139.60705614794117", "latitude": "35.713942413120606"}
to actually access my object, I need to do the following
temp1["\"heading\""]
because there is actually those \"key\" everywhere
but I don't see a good way to remove them
I tried
(obj, title, index) => {title = title.replace('\"', ''); return ((obj[title] = values[index]), obj); },
but it remove only one \ (so it becomes like this)

Javascript Node js search and return lines that contain a string in a file

I am new to javascript and struggling to come up with a solution. I have got a file that contains lines in JSON format. In the below code I have converted the JSON to objects and trimmed the white space on each line and returned the output.
Now, I need to not only remove the white spaces but to even search for a string(provided by the user and passed in as a variable) in each line of the file and if the string found it should return the entire line.
I tried .includes(req.params.msg) but couldn't get to right.
get(req, res) {
let arry = [];
const text = (fs.readFileSync('./pretty.out'));
arry = (text.toString().split('\n'));
let wat = [];
arry.forEach(i => {
if (!!i.trim()) {
wat.push(JSON.parse(i));
}
});
res.json(wat);
}
File's content will be,
{"foo" : "bar","bar" : "sit"}
{"foo" : "lorem","bar" : "ipsum"}
{"foo" : "dolor","bar" : "amet"}
If the user inputs sit then the output should be,
{"foo" : "bar","bar" : "sit"}
// using fs.readFileSync is fine, but only during process boot time
// if the data is dynamic you'll need to read it async
const data = (fs.readFileSync('./pretty.out'), 'utf8')
.split('\n')
.filter(line => line.trim())
.map(line => JSON.parse(line));
// input should use post requests
post(req, res) {
const query = req.body;
let results = data.filter(d => d.bar === query);
res.json(results);
}
Looks like you've got it in array format now, so this should work fine:
// To return multiple query matches:
function search(query){
return arr.filter(function(item){
return JSON.stringify(item).match(query) !== null;
})
}
// To return single (first) query match:
function search(query){
return arr.find(function(item){
return JSON.stringify(item).match(query) !== null;
})
}
If you're not converting it to an array of json object you can use:
function search(query){
return file.match(new RegExp("{.+"+query+".+}", "g"))
}
Here's a fiddle:
https://jsfiddle.net/1cqacj3b/11/ (modified to show results in html

JS - Pushing data into JSON structure using forEach loops on Arrays

I am attempting to extract JSON values (from structure called jsonWithListOfStatesAndCounters) if it matches with an element in my inputted array (inputedJurisdictionArray). My inputed array contains sting values that include singular or multiple state names (i.e. var inputedJurisdictionArray = ["Iowa", "California, Indiana, Delaware", "Florida"]). The singular State values in this array are handled normally at the end, but the multiple state values is where it gets tricky. I am using split() in order to turn them into another array so they can get processed one by one. Anytime one of the states from this inputed array matches with a "state" value in jsonWithListOfStatesAndCounters, I am extracting it into another JSON structure and pushing it at the end of every block into my initial variable myJurisdictionJSON. The problem I am having is that once these forEach loops are completed, I am still left with my original values in myJurisdictionJSON, instead of the val and counter that should be extracted. The jsonWithListOfStatesAndCounters definitely contains the values that should match with the elements of my inputedJurisdictionArray, but the information is not being pushed into myJurisdictionJSON. What am I doing wrong? Any tips/pointers will be helpful.
var myJurisdictionJSON = [{
jurisdiction_val: 'jurisdiction_val',
jurisdiction_counter: 'jurisdiction_counter'
}];
inputedJurisdictionArray.forEach(function each(item) {
if (Array.isArray(item)) {
item.forEach(each);
} else {
var jurisdictionInput = item;
jsonWithListOfStatesAndCounters.forEach(function each(item) {
if (Array.isArray(item)) {
item.forEach(each);
} else {
if (jurisdictionInput.includes(",") === true){//Checking if more than one jurisdiction in string
var jurisdictionArr = jurisdictionInput.split(", ");
var jurisdictionCounter = item.jurisdictionCounter;
var jurisdictionState = item.jurisdictionState;
jurisdictionArr.forEach(function(element) {
if (myJurisdictionJSON.jurisdiction_counter == 'jurisdiction_counter'){ // If nothing is pushed into our predefined JSON object
if (jurisdictionState.toLowerCase() == trim(element.toLowerCase())) {
var jurisdictionJSON_inner = {
jurisdiction_val: element,
jurisdiction_counter: jurisdictionCounter
};
myJurisdictionJSON.push(jurisdictionJSON_inner);
return;
}
}else if (myJurisdictionJSON.jurisdiction_counter != 'jurisdiction_counter'){ // if an item has been pushed into myJurisdictionJSON, append the next items
var jurisdictionCounter = item.jurisdictionCounter;
var jurisdictionState = item.jurisdictionState;
if (jurisdictionState.toLowerCase() == trim(jurisdictionInput.toLowerCase())) {
jurisdictionJSON_inner.jurisdiction_val = jurisdictionJSON_inner.jurisdiction_val + ", " + jurisdictionInput;
jurisdictionJSON_inner.jurisdiction_counter = jurisdictionJSON_inner.jurisdiction_counter + ", " + jurisdictionCounter;
myJurisdictionJSON.push(jurisdictionJSON_inner);
return;
}
}
});
}
else{// if only one jurisdiction state in jurisdictionInput string
var jurisdictionCounter = item.jurisdictionCounter;
var jurisdictionState = item.jurisdictionState;
if (jurisdictionState.toLowerCase() == trim(jurisdictionInput.toLowerCase())) {
var jurisdictionJSON_inner = {
jurisdiction_val: jurisdictionInput,
jurisdiction_counter: jurisdictionCounter
};
myJurisdictionJSON.push(jurisdictionJSON_inner);
return;
}
}
}
});
I'm not totally sure the output is what you want but it's close.
// input data as per your example
let inputedJurisdictionArray = [
'Iowa',
'California, Indiana, Delaware',
'Florida'
];
// I had to make this part up. It's missing from the example
let jsonWithListOfStatesAndCounters = [{
jurisdictionCounter: 2,
jurisdictionState: 'Florida'
},
{
jurisdictionCounter: 4,
jurisdictionState: 'Indiana'
},
{
jurisdictionCounter: 3,
jurisdictionState: 'Texas'
}
];
// first, fix up inputedJurisdictionArray
// reduce() loops over each array element
// in this case we're actually returning a LARGER
// array instead of a reduced on but this method works
// There's a few things going on here. We split, the current element
// on the ','. Taht gives us an array. We call map() on it.
// this also loops over each value of the array and returns an
// array of the same length. So on each loop, trim() the whitespace
// Then make the accumulator concatenate the current array.
// Fat arrow ( => ) functions return the results when it's one statement.
inputedJurisdictionArray = inputedJurisdictionArray.reduce(
(acc, curr) => acc.concat(curr.split(',').map(el => el.trim())), []
);
// now we can filter() jsonWithListOfStatesAndCounters. Loop through
// each element. If its jurisdictionState property happens to be in
// the inputedJurisdictionArray array, then add it to the
// myJurisdictionJSON array.
let myJurisdictionJSON = jsonWithListOfStatesAndCounters.filter(el =>
inputedJurisdictionArray['includes'](el.jurisdictionState)
);
console.log(myJurisdictionJSON);

Categories

Resources