59

我已经关注了这篇文章如何将 JavaScript 数组信息导出到 csv(在客户端)?将嵌套的 js 数组写入 csv 文件。

数组看起来像:

var test_array = [["name1", 2, 3], ["name2", 4, 5], ["name3", 6, 7], ["name4", 8, 9], ["name5", 10, 11]];

链接中给出的代码运行良好,除了在 csv 文件的第三行之后,所有其余的值都在同一行,例如

name1,2,3
name2,4,5
name3,6,7
name4,8,9name5,10,11 等

任何人都可以解释为什么会这样吗?同样使用 Chrome 或 FF。

谢谢

编辑

jsfiddle http://jsfiddle.net/iaingallagher/dJKz6/

伊恩

4

10 回答 10

93

引用的答案是错误的。你必须改变

csvContent += index < infoArray.length ? dataString+ "\n" : dataString;

csvContent += dataString + "\n";

至于为什么引用的答案是错误的(有趣的是它已被接受!):回调函数index的第二个参数forEach是循环数组中的索引,将其与 的大小进行比较是没有意义的infoArray,是所述数组的一项(恰好也是一个数组)。

编辑

自从我写下这个答案以来,已经过去了六年。许多事情都发生了变化,包括浏览器。以下是答案的一部分:

老化部分的开始

顺便说一句,引用的代码不是最理想的。您应该避免重复附加到字符串。您应该改为附加到数组,并在最后执行 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");

老化部分的结束

(请记住,CSV 案例与通用字符串连接有点不同,因为对于每个字符串,您还必须添加分隔符。)

无论如何,以上内容似乎不再适用,至少对于 Chrome 和 Firefox 来说不是这样(不过,对于 Safari 来说似乎仍然如此)。

为了结束不确定性,我编写了一个jsPerf 测试,测试是否为了以逗号分隔的方式连接字符串,将它们推入数组并加入数组,或者先用逗号连接它们是否更快,然后使用 += 运算符直接使用结果字符串。

请点击链接并运行测试,以便我们有足够的数据来谈论事实而不是意见。

于 2013-09-17T11:55:25.260 回答
30

一般形式为:

var ids = []; <= this is your array/collection
var csv = ids.join(",");

对于您的情况,您将不得不稍作调整

于 2014-02-26T03:40:58.843 回答
27

对于一个简单的 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

此方法还允许您在内部指定除逗号以外的列分隔符join。例如一个标签:d.join('\t')

另一方面,如果您想正确执行此操作并将字符串括在引号中"",那么您可以使用一些 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

如果您有一组对象,例如:

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, '');
于 2015-04-30T19:51:50.353 回答
16

我创建了这段代码来创建一个漂亮、可读的 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); 
}

在您的情况下,由于您在数组中使用数组而不是数组中的对象,因此您将跳过标题部分,但您可以自己添加列名,方法是放置此部分而不是该部分:

// headers
csvContent += '"Column name 1" "Column name 2" "Column name 3"\n';

秘诀是用空格分隔 csv 文件中的列,我们将列值放在双引号中以允许空格,并转义值本身中的任何双引号。

另请注意,我用空字符串替换空值,因为这适合我的需要,但您可以更改它并用您喜欢的任何内容替换它。

于 2016-06-24T19:59:18.723 回答
8

如果您的数据包含任何换行符或逗号,您需要先转义这些:

const escape = text =>
    text.replace(/\\/g, "\\\\")
        .replace(/\n/g, "\\n")
        .replace(/,/g, "\\,")

escaped_array = test_array.map(fields => fields.map(escape))

然后只需执行以下操作:

csv = escaped_array.map(fields => fields.join(","))
                .join("\n")

如果你想让它在浏览器中可下载:

dl = "data:text/csv;charset=utf-8," + csv
window.open(encodeURI(dl))
于 2016-11-17T14:41:32.557 回答
5

以下代码是用 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);

于 2019-04-24T13:01:33.057 回答
0

选择的答案可能是正确的,但似乎不必要地不清楚。

我发现Shomz's Fiddle很有帮助,但又一次不必要地不清楚。(编辑:我现在看到 Fiddle 基于 OP 的 Fiddle。)

这是我认为更清楚的版本(我为此创建了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));
});
于 2016-12-07T21:16:21.280 回答
0

ES6:

let csv = test_array.map(row=>row.join(',')).join('\n') 
//test_array being your 2D array
于 2020-10-31T05:40:05.273 回答
-1
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
于 2019-05-01T17:07:27.260 回答
-1

如果你使用 React 并且想在客户端生成一个 CSV 文件,你可以这样做:

import CsvGenerator from '@exlabs/react-csv-generator';

const data = [{ id: 1, name: 'first' }, { id: 2, name: 'second' }];

const MyComponent = () => {
  return (
    <CsvGenerator fileName="my-name" items={data}>
      Download!
    </CsvGenerator>
  );
};

重要的是,它的包很轻,并且支持 Excel 和 Numbers。

链接到 npm 包

于 2021-07-09T12:37:40.963 回答