4

I'm new to JS and not much exp in Regex to play with string manipulation.

Here is my CSV file with records in tabular form with the first line as headers and from on next line the values will be present:

Name  City   Country
John  Chennai IN
Ken   Brisban AUS
Ben   NY      US

I need the output in a array of objects like this:

[
{Name: 'John',City: "Chennai",Country:"IN"}
{Name: 'Ken',City: "Brisbane",Country:"AUS"}
{Name: 'Ben',City: "NY",Country:"US"}
]

I'm uploading a CSV file and need to save those records in to DB and below is the code block which will be triggered after I upload the CSV and I tried to parse the CSV records with below:

        $scope.processFiles = function() {
            //var input = document.getElementById("fileOutput");
            var input = document.querySelector('input[type = "file"]')
            var file = input.files[0];
            var reader = new FileReader();
            var output;
            reader.onload = function (e) {
                var csvToText = e.target.result;
                output = csvToJSON(csvToText);
                console.log(output);
            };
            reader.readAsText(file);
            event.preventDefault();
        }

        function csvToJSON(csv) {
            var lines = csv.split("\n");
            var result = [];
            var headers;
            for (var i = 0; i < lines.length; i++) {
                headers = lines[i].split("\n");
            }
            var cont = 0;
            for (var i = 0; i < lines.length; i++) {

                var obj = {};
                var currentline = lines[i].split("\n");
                for (var j = 0; j < headers.length; j++) {
                    obj[cont] = currentline[j];
                }
                cont++;
                result.push(obj);
            }
            console.log(result);
            //console.log(JSON.stringify(result));

            //return result;
        }

The output I'm getting is below i.e. the values are shown in one line with comma separators and the fourth array element is not supposed to display.

0: {0: "Name,City,Country"}
1: {1: "John,Chennai,IN"}
2: {2: "Ken,Brisbane,AUS"}
3: {3: "Ben,NY,USA"}
4: {4: ""}

6 Answers 6

6

I have corrected your function to return the output in the desired format:

function csvToJSON(csv) {
    var lines = csv.split("\n");
    var result = [];
    var headers;
    headers = lines[0].split(",");

    for (var i = 1; i < lines.length; i++) {
        var obj = {};

        if(lines[i] == undefined || lines[i].trim() == "") {
            continue;
        }

        var words = lines[i].split(",");
        for(var j = 0; j < words.length; j++) {
            obj[headers[j].trim()] = words[j];
        }

        result.push(obj);
    }
    console.log(result);
}
Sign up to request clarification or add additional context in comments.

5 Comments

But the third object name (country) is surrounded by double quotes - like this "country", can you please help on it
@Mar1009 Didn't quite get the problem. Can you please explain with an example?
0: {Name: "John", City: "Chennai", "Country ": "IN"} 1: {Name: "Ken", City: "Brisbane", "Country ": "AUS"} 2: {Name: "Ben", City: "NY", "Country ": "USA"} 3: {Name: ""} as you can see the Country is double quoted, I need to get rid of that
@Mar1009 Fixed that. Give it a try now.
Thanks Arun it is okay now
1

First, parse the CSV text into an array:

function parseCsv (data) {
  const re = /(,|\r?\n|\r|^)(?:"([^"]*(?:""[^"]*)*)"|([^,\r\n]*))/gi
  const result = [[]]
  let matches
  while ((matches = re.exec(data))) {
    if (matches[1].length && matches[1] !== ',') result.push([])
    result[result.length - 1].push(
      matches[2] !== undefined ? matches[2].replace(/""/g, '"') : matches[3]
    )
  }
  return result
}

Then read the headers and return an array of objects:

function arrayToObject (csvArray) {

  //Take the first line (headers) from the array and remove it from the array.
  const headers = csvArray.shift() 

  // Iterate through the rows and reduce each column to an object
  return csvArray.map(row => headers.reduce((acc, currentHeader, i) => ({ ...acc, ...{ [currentHeader]: row[i] } }), {}))
}

How to use:

const csvArray = parseCsv(csvText)
const arrayOfObjects = arrayToObject(csvArray)

Thanks to Jezternz for the CSV parser

Comments

0

Try this.

function csvToJSON(csv) {

    //lop off any trailing or starting whitespace
    csv = csv.trim();

    //prep
    let lines = csv.split('\n'),
        headers,
        output = [];

    //iterate over lines...
    lines.forEach((line, i) => {

        //...break line into tab-separated parts
        let parts = line.split(/\t+/);

        //...if not the headers line, push to output. By this time
       //we have the headers logged, so just match the value to
       //header of the same index
        if (i) {
            let obj = {};
            parts.forEach((part, i) => obj[headers[i]] = part);
            output.push(obj);

        //...else if headers line, log headers
        } else
            headers = parts;
    })

    //done
    console.log(output);
    return output;
}

CodePen. (Note: in the CodePen, I'm reading the CSV from an HTML div, hence the minor difference in the code.)

Comments

0

Something like this should work

function csvToJSON(csv) {
            var lines = csv.split("\n");
            var result = [];
            var headers = lines[0].split(",");

            lines.forEach( (line, index) => {
              if (index === 0) continue // skip the first line (headers)

              let data = {};
              let cells = line.split(",") // separate by commas
              cells.forEach( (cell, index) => {
                let header = headers[index];
                data[header] = cell;
              }
              result.push(data);
            }

            console.log(result);
            //console.log(JSON.stringify(result));

            return result;
        }

Comments

0
let lines = string.split("\n");
let result = [];
let headers;
headers = lines[0].split(",");
for (let i = 1; i < lines.length; i++) {
    let obj = {};
    if(lines[i] == undefined || lines[i].trim() == "") {
        continue;
    }
    let words = lines[i].split(",");
    for (var j = 0; j < words.length; j++) {
        obj[headers[j].trim().replace(/(\r\n|\n|\r)/gm, "")] = 
        words[j].replace(/(\r\n|\n|\r)/gm, "");
        }
   result.push(obj);
   }
   console.log(result);

1 Comment

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
0

Simple and flexible function, accepting both tabs, double space, comma and semicolon, as column separator.

It could accept multiples columns of course.

/* FLEXIBLE CSV PARSER BY NVRM */
const parseCSV = (csv) => {
  csv = csv.replaceAll(";", "  ")
  return csv.split('\n')
    .map(row => row.replace(/ |  |\t/g, ',')
    .split(',')
    .filter(r => r != '')
  )
}

/* --- TESTS --- */
console.log(

// Tabular separators (OP query)
parseCSV(`Name  City   Country
John    Chennai IN
Ken     Brisban AUS
Ben   NY      US`)   

, 

// Comma separator
parseCSV(`YEAR,POPULATION
1960,56
1970,59
1980,56
1990,58
2000,60
2010,65
2020,67`)

,

// Double space separator
parseCSV(`YEAR,POPULATION
1960  956  100
1970  959  200
1980  956  300
1990  958  400
2000  960  550
2010  965  700
2020  967  800`)

,

// Semicolon separator
parseCSV(`YEAR;POPULATION
2060;956;11
2070;959;12
2080;956;13
2090;958;14
3000;960;15
3010;965;16
3020;967;17`)

)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.