Как преобразовать csv в JSON, когда строка имеет два значения для одного столбца в узле js
У меня есть csv
файл, в котором строка иногда имеет два значения для столбца. В настоящее время я пытаюсь разделить, используя,
но работает не так, как ожидалось. Может кто-нибудь пролить свет на то, как добиться ожидаемого результата. Я не хочу использоватьnpm
библиотека.
//users.csv
name,age,hobbies
james,20,"reading,playing"
marie,18,singing
peter,19,watching movies
//index.js
const fs = require('fs');
const {promisify} = require("util");
const readFile = promisify(fs.readFile)
const readSheet = async () =>{
const result = await readFile("./users.csv", "utf-8");
const csv = result.split("\n").map(ele=>ele.split(","))
let keys = csv.slice(0,1)[0];
const values = csv.slice(1)
keys.map(keys=>keys.split(''))
let usersArr = [];
for(let i = 0;i<values.length;i++){
let usersObj = {};
keys.forEach((key,j)=>usersObj[key] = values[i][j])
usersArr.push(usersObj)
}
return usersArr
}
//current output
[ { name: 'james', age: '20', hobbies: '"reading' },
{ name: 'marie', age: '18', hobbies: 'singing' },
{ name: 'peter', age: '19', hobbies: 'watching movies' } ]
//expected output object
[
{
"name": "james",
"age": 20,
"hobbies": ["reading","playing"]
},
{
"name": "marie",
"age": 18,
"hobbies": ["singing"]
},
{
"name": "peter",
"age": 19,
"hobbies": ["watching movies"]
}
]
2 ответа
Вы можете использовать функцию csv, описанную в этой статье блога: https://www.bennadel.com/blog/1504-ask-ben-parsing-csv-strings-with-javascript-exec-regular-expression-command.htm
Затем преобразуйте массивы в объекты:
let csv = ... // csv data
for(let i=1;i<csv.length;i++){
let obj = {};
for(let b in csv[i]){
obj[csv[0][b]] = csv[i][b];
}
csv[i] = obj;
}
csv.shift(); // remove the first row (headers)
После этого просто разделите столбец хобби в массиве запятой:
for(let entry of csv){
csv.hobbies = csv.hobbies.split(',');
}
Разделение каждой строки запятой не сработает, поскольку кавычки окружены запятой. Лучшим вариантом будет использование библиотеки изnpm
Такие как fast-csv
. Поскольку вы не хотите использовать библиотеку, вы можете использовать регулярное выражение для разделения строки, как описано в этом вопросе:
Вот пример рабочего кода (однако помните об ограничениях):
const fs = require('fs');
const {promisify} = require("util");
const readFile = promisify(fs.readFile)
const CSV_CONTENT = "name,age,hobbies\njames,20,\"reading,playing\"\nmarie,18,singing\npeter,19,watching movies\n";
const readSheet = async () => {
//const lines = await readFile("./users.csv", "utf-8");
const lines = CSV_CONTENT.split("\n")
.filter(l => !!l) // filter empty lines
let keys = lines.slice(0,1)[0].split(',') // assuming there's no quotes in keys
const valueLines = lines.slice(1)
let usersArr = [];
for(let i=0; i<valueLines.length; i++) {
let usersObj = {};
let values = splitLine(valueLines[i]); // splitLine handles quotes
keys.forEach((key,j) => usersObj[key] = trimQuotes(values[j]))
usersArr.push(usersObj)
}
return usersArr
}
function splitLine(line) {
var matches = line.match(/(\s*"[^"]+"\s*|\s*[^,]+|,)(?=,|$)/g);
for (var n = 0; n < matches.length; ++n) {
matches[n] = matches[n].trim();
if (matches[n] == ',') matches[n] = '';
}
if (line[0] == ',') matches.unshift("");
return matches;
}
function trimQuotes(input) {
let expr = /^(")?(.*?)(")?$/g
let groups = expr.exec(input)
return groups[2]
}
(async () => {
let result = await readSheet();
console.log(result);
})();