JavaScript 数组到 CSV

Posted

技术标签:

【中文标题】JavaScript 数组到 CSV【英文标题】:JavaScript array to CSV 【发布时间】:2013-09-21 19:59:54 【问题描述】:

我已经关注了这篇帖子How to export javascript array info to csv (on client side)? 来获取一个嵌套的 js 数组,该数组写为 csv 文件。

数组看起来像:

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

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

名称1,2,3 名称2,4,5 名称3,6,7 name4,8,9name5,10,11 等

谁能解释这是为什么?同样使用 Chrome 或 FF。

谢谢

编辑

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

伊恩

【问题讨论】:

【参考方案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。

Link to the npm package

【讨论】:

【参考方案2】:

ES6:

let csv = test_array.map(row=>row.join(',')).join('\n') 
//test_array being your 2D array

【讨论】:

【参考方案3】:

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

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

csvContent += dataString + "\n";

至于为什么引用的答案是错误的(有趣的是它被接受了!):indexforEach回调函数的第二个参数,是循环数组中的索引,没有意义将其与infoArray 的大小进行比较,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 test 来测试,为了以逗号分隔的方式连接字符串,将它们推入数组并加入数组,或者先连接它们是否更快使用逗号,然后使用 += 运算符直接使用结果字符串。

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

【讨论】:

您确定字符串 += 不是最优的吗? This article 似乎另有说法。 fname 怎么样?这些文件只是命名为下载,而不是 .csv 文件 如果其中一个值中有'\n'或',',它将中断。 @WalterTross 完美!谢谢!那完美无瑕!此外,我使用链接 [1] 下载内容。基本上使用BlobURL。 [1]***.com/a/24922761/334872 并且,使用这个解决方案,我删除了 csvContentArray 的第一个条目(“assigning data:text.......”),因为它不再需要了。【参考方案4】:

对于一个简单的 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, '');

【讨论】:

不起作用。在示例中对第二种格式的数据进行了测试。 是否在某处定义了“值”? @OGSean 'values' 是 'Object.values'。见developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…。为了清楚起见,我更新了代码示例。谢谢【参考方案5】:
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

【讨论】:

对我不起作用【参考方案6】:

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

【讨论】:

如果数据有 # 字符失败。代替 encodeUri,encodeUriComponent 解决了 # 字符的问题。 `encodeURIComponent('a#b') "a%23b" encodeURI('a#b') "a#b" `【参考方案7】:

我创建了这段代码来创建一个漂亮、可读的 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 文件中的列,我们将列值放在双引号中以允许空格,并转义值本身中的任何双引号。

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

【讨论】:

【参考方案8】:

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

我发现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));
);

【讨论】:

【参考方案9】:

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

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))

【讨论】:

转义函数可能不是 100% 正确,但它应该为您指明正确的方向。 要在 CSV 中包含新行 (\n),您只需将包含新行的字符串用引号括起来。要将字符串括在引号中,您需要转义此字符串中的引号) 错误:fields.map 不是函数【参考方案10】:

一般形式是:

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

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

【讨论】:

此答案假定要导出的数组中没有“特殊”字符(没有逗号,没有引号)。如果有,此答案将不起作用。

以上是关于JavaScript 数组到 CSV的主要内容,如果未能解决你的问题,请参考以下文章

在JavaScript中将一个数组附加到另​​一个数组[重复]

PHP数组()到javascript数组()[重复]

php数组加载到javascript中

Javascript:求和到数组

Javascript :: 如何将关联数组的键获取到数组变量?

将数组从 EJS 传递到 Javascript