我正在使用Node 的 CSV 包来解析项目中的一些 CSV 文件。我需要能够处理有和没有标题的案例。所以:
const withHeader = `h1,h2,h3
d1a,d2a,d3a
d1b,d2b,d3b`;
const withoutHeader = `d1a,d2a,d3a
d1b,d2b,d3b`;
我的应用程序不知道列数及其名称。它们要么从标题中读取,要么应该以数字方式生成,例如col0,col1,col2.
这是我遇到问题的地方。我总是希望csvParse的输出采用对象文字形式。当最终用户指示 CSV 具有标题时,这很容易:
> csvParse(withHeader, {columns: true})
[
{ h1: 'd1a', 'h2': 'd2a', 'h3': 'd3a' },
{ h1: 'd1b', 'h2': 'd2b', 'h3': 'd3b' }
]
但是,当用户指出没有标题行时,似乎不可能以对象文字形式使用程序生成的列标题来结束数据。
的 3 个选项columns是boolean | array | function。
- 通过提供
false,返回的数据是一个数组数组,然后我需要将其转换为对象文字形式。不理想! - 要提供列名数组,我已经需要知道有多少列......在解析之前,这是没有意义的。我可以解析第一行以获取计数,然后重新开始提供数组,但这似乎很笨拙。
- 我可以提供一个以编程方式生成列键的函数。例如
column => column,这无济于事,因为 a) 没有提供索引,并且 b) 然后忽略第一行,因为它被假定为将列标题转换为所需的列键。
有没有我错过的方法来做到这一点?以下是两种看似笨拙且效率较低的方法。
解析 1 行,然后解析所有
// Obviously in actual use I'd handle edge cases
const colCount = csvParse(withoutHeader, {to_line: 1})[0].length;
// 3
const data = csvParse(withoutHeader, {columns: [...Array(colCount).keys()].map(i => `col{i}`)})
/*
[
{ col0: 'd1a', col1: 'd2a', col2: 'd3a' },
{ col0: 'd1b', col1: 'd2b', col2: 'd3b' }
]
*/
解析成数组数组,然后转换
csvParse(withoutHeader).map(
row => row.reduce(
(obj, item, index) => {
obj[`col${index}`] = item;
return obj;
},
{}
)
)
/*
[
{ col0: 'd1a', col1: 'd2a', col2: 'd3a' },
{ col0: 'd1b', col1: 'd2b', col2: 'd3b' }
]
*/
对我来说,能够指定columns为一个函数是理想的,它被赋予列索引作为参数而不是标题行。