JavaScript 数组转 CSV
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18848860/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JavaScript array to CSV
提问by duff
I've followed this post How to export JavaScript array info to csv (on client side)?to get a nested js array written as a csv file.
我已经关注了这篇文章如何将 JavaScript 数组信息导出到 csv(在客户端)?将嵌套的 js 数组写入 csv 文件。
The array looks like:
该数组看起来像:
var test_array = [["name1", 2, 3], ["name2", 4, 5], ["name3", 6, 7], ["name4", 8, 9], ["name5", 10, 11]];
The code given in the link works nicely except that after the third line of the csv file all the rest of the values are on the same line e.g.
链接中给出的代码工作得很好,除了在 csv 文件的第三行之后,所有其余的值都在同一行上,例如
name1,2,3
name2,4,5
name3,6,7
name4,8,9name5,10,11 etc etc
name1,2,3
name2,4,5
name3,6,7
name4,8,9name5,10,11 等等
Can anyone shed any light on why this is? Same using Chrome or FF.
任何人都可以解释为什么会这样吗?同样使用 Chrome 或 FF。
Thanks
谢谢
EDIT
编辑
jsfiddle http://jsfiddle.net/iaingallagher/dJKz6/
jsfiddle http://jsfiddle.net/iaingallagher/dJKz6/
Iain
伊恩
回答by Walter Tross
The cited answer was wrong. You had to change
引用的答案是错误的。你必须改变
csvContent += index < infoArray.length ? dataString+ "\n" : dataString;
to
到
csvContent += dataString + "\n";
As to why the cited answer was wrong (funny it has been accepted!): index
, the second parameter of the forEach
callback function, is the index in the looped-upon array, and it makes no sense to compare this to the size of infoArray
, which is an item of said array (which happens to be an array too).
至于为什么引用的答案是错误的(有趣的是它已被接受!):回调函数index
的第二个参数forEach
是循环数组中的索引,将其与 的大小进行比较是没有意义的infoArray
,其中是所述数组的一个项目(它也恰好是一个数组)。
EDIT
编辑
Six years have passed now since I wrote this answer. Many things have changed, including browsers. The following was part of the answer:
自从我写下这个答案以来,已经过去了六年。许多事情都发生了变化,包括浏览器。以下是答案的一部分:
START of aged part
老化部分的开始
BTW, the cited code is suboptimal. You should avoid to repeatedly append to a string. You should append to an array instead, and do an array.join("\n") at the end. Like this:
顺便说一句,引用的代码是次优的。您应该避免重复附加到字符串。您应该改为附加到一个数组,并在最后执行一个 array.join("\n") 。像这样:
var lineArray = [];
data.forEach(function (infoArray, index) {
var line = infoArray.join(",");
lineArray.push(index == 0 ? "data:text/csv;charset=utf-8," + line : line);
});
var csvContent = lineArray.join("\n");
END of aged part
老化部分结束
(Keep in mind that the CSV case is a bit different from generic string concatenation, since for every string you also have to add the separator.)
(请记住,CSV 大小写与通用字符串连接有点不同,因为对于每个字符串,您还必须添加分隔符。)
Anyway, the above seems notto be true anymore, at least not for Chrome and Firefox (it seems to still be true for Safari, though).
无论如何,以上似乎不再正确,至少对于 Chrome 和 Firefox 来说不是这样(不过,对于 Safari 似乎仍然如此)。
To put an end to uncertainty, I wrote a jsPerf testthat tests whether, in order to concatenate strings in a comma-separated way, it's faster to push them onto an array and join the array, or to concatenate them first with the comma, and then directly with the result string using the += operator.
为了结束不确定性,我编写了一个jsPerf 测试来测试,为了以逗号分隔的方式连接字符串,是将它们推送到数组并加入数组更快,还是先用逗号连接它们,然后直接使用 += 运算符处理结果字符串。
Please follow the link and run the test, so that we have enough data to be able to talk about facts instead of opinions.
请按照链接运行测试,以便我们有足够的数据来谈论事实而不是观点。
回答by Mircea Stanciu
General form is:
一般形式为:
var ids = []; <= this is your array/collection
var csv = ids.join(",");
For your case you will have to adapt a little bit
对于你的情况,你将不得不适应一点
回答by Konstantin
for a simple csv one map() and a join() are enough:
对于一个简单的 csv,一个 map() 和一个 join() 就足够了:
var csv = test_array.map(function(d){
return d.join();
}).join('\n');
/* Results in
name1,2,3
name2,4,5
name3,6,7
name4,8,9
name5,10,11
This method also allows you to specify column separator other than a comma in the inner join
. for example a tab: d.join('\t')
此方法还允许您在内部指定逗号以外的列分隔符join
。例如一个标签:d.join('\t')
On the other hand if you want to do it properly and enclose strings in quotes ""
, then you can use some JSON magic:
另一方面,如果你想正确地做到这一点并将字符串括在引号中""
,那么你可以使用一些 JSON 魔法:
var csv = test_array.map(function(d){
return JSON.stringify(d);
})
.join('\n')
.replace(/(^\[)|(\]$)/mg, ''); // remove opening [ and closing ] brackets from each line
/* would produce
"name1",2,3
"name2",4,5
"name3",6,7
"name4",8,9
"name5",10,11
if you have array of objects like :
如果你有像这样的对象数组:
var data = [
{"title": "Book title 1", "author": "Name1 Surname1"},
{"title": "Book title 2", "author": "Name2 Surname2"},
{"title": "Book title 3", "author": "Name3 Surname3"},
{"title": "Book title 4", "author": "Name4 Surname4"}
];
// use
var csv = data.map(function(d){
return JSON.stringify(Object.values(d));
})
.join('\n')
.replace(/(^\[)|(\]$)/mg, '');
回答by Frane Poljak
I created this code for creating a nice, readable csv files:
我创建了这个代码来创建一个漂亮的、可读的 csv 文件:
var objectToCSVRow = function(dataObject) {
var dataArray = new Array;
for (var o in dataObject) {
var innerValue = dataObject[o]===null?'':dataObject[o].toString();
var result = innerValue.replace(/"/g, '""');
result = '"' + result + '"';
dataArray.push(result);
}
return dataArray.join(' ') + '\r\n';
}
var exportToCSV = function(arrayOfObjects) {
if (!arrayOfObjects.length) {
return;
}
var csvContent = "data:text/csv;charset=utf-8,";
// headers
csvContent += objectToCSVRow(Object.keys(arrayOfObjects[0]));
arrayOfObjects.forEach(function(item){
csvContent += objectToCSVRow(item);
});
var encodedUri = encodeURI(csvContent);
var link = document.createElement("a");
link.setAttribute("href", encodedUri);
link.setAttribute("download", "customers.csv");
document.body.appendChild(link); // Required for FF
link.click();
document.body.removeChild(link);
}
In your case, since you use arrays in array instead of objects in array, You will skip the header part, but you could add the column names yourself by putting this instead of that part:
在您的情况下,由于您使用数组中的数组而不是数组中的对象,因此您将跳过标题部分,但您可以通过放置此部分而不是该部分来自行添加列名:
// headers
csvContent += '"Column name 1" "Column name 2" "Column name 3"\n';
The secret is that a space separates the columns in the csv file, and we put the column values in the double quotes to allow spaces, and escape any double quotes in the values themselves.
秘诀是用空格分隔 csv 文件中的列,我们将列值放在双引号中以允许空格,并转义值本身中的任何双引号。
Also note that I replace null values with empty string, because that suited my needs, but you can change that and replace it with anything you like.
另请注意,我用空字符串替换了空值,因为这符合我的需要,但您可以更改它并将其替换为您喜欢的任何内容。
回答by Zaz
If your data contains any newlines or commas, you will need to escape those first:
如果您的数据包含任何换行符或逗号,您需要先转义它们:
const escape = text =>
text.replace(/\/g, "\\")
.replace(/\n/g, "\n")
.replace(/,/g, "\,")
escaped_array = test_array.map(fields => fields.map(escape))
Then simply do:
然后简单地做:
csv = escaped_array.map(fields => fields.join(","))
.join("\n")
If you want to make it downloadable in-browser:
如果要使其可在浏览器中下载:
dl = "data:text/csv;charset=utf-8," + csv
window.open(encodeURI(dl))
回答by B.Balamanigandan
The following code were written in ES6 and it will work in most of the browsers without an issue.
以下代码是用 ES6 编写的,它可以在大多数浏览器中正常运行。
var test_array = [["name1", 2, 3], ["name2", 4, 5], ["name3", 6, 7], ["name4", 8, 9], ["name5", 10, 11]];
// Construct the comma seperated string
// If a column values contains a comma then surround the column value by double quotes
const csv = test_array.map(row => row.map(item => (typeof item === 'string' && item.indexOf(',') >= 0) ? `"${item}"`: String(item)).join(',')).join('\n');
// Format the CSV string
const data = encodeURI('data:text/csv;charset=utf-8,' + csv);
// Create a virtual Anchor tag
const link = document.createElement('a');
link.setAttribute('href', data);
link.setAttribute('download', 'export.csv');
// Append the Anchor tag in the actual web page or application
document.body.appendChild(link);
// Trigger the click event of the Anchor link
link.click();
// Remove the Anchor link form the web page or application
document.body.removeChild(link);
回答by Jason Swett
The selected answer is probably correct but it seems needlessly unclear.
所选答案可能是正确的,但似乎不必要地不清楚。
I found Shomz's Fiddleto be very helpful, but again, needlessly unclear. (Edit: I now see that that Fiddle is based on the OP's Fiddle.)
我发现Shomz 的 Fiddle非常有帮助,但同样,不必要地不清楚。(编辑:我现在看到那个 Fiddle 是基于 OP 的 Fiddle。)
Here's my version (which I've created a Fiddlefor) which I think is more clear:
这是我的版本(我为它创建了一个Fiddle),我认为它更清楚:
function downloadableCSV(rows) {
var content = "data:text/csv;charset=utf-8,";
rows.forEach(function(row, index) {
content += row.join(",") + "\n";
});
return encodeURI(content);
}
var rows = [
["name1", 2, 3],
["name2", 4, 5],
["name3", 6, 7],
["name4", 8, 9],
["name5", 10, 11]
];
$("#download").click(function() {
window.open(downloadableCSV(rows));
});
回答by Jelle Hak
const escapeString = item => (typeof item === 'string') ? `"${item}"` : String(item)
const arrayToCsv = (arr, seperator = ';') => arr.map(escapeString).join(seperator)
const rowKeysToCsv = (row, seperator = ';') => arrayToCsv(Object.keys(row))
const rowToCsv = (row, seperator = ';') => arrayToCsv(Object.values(row))
const rowsToCsv = (arr, seperator = ';') => arr.map(row => rowToCsv(row, seperator)).join('\n')
const collectionToCsvWithHeading = (arr, seperator = ';') => `${rowKeysToCsv(arr[0], seperator)}\n${rowsToCsv(arr, seperator)}`
// Usage:
collectionToCsvWithHeading([
{ title: 't', number: 2 },
{ title: 't', number: 1 }
])
// Outputs:
"title";"number"
"t";2
"t";1