Массив JavaScript в CSV

Я следил за этим сообщением Как экспортировать информацию о массиве 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/

Иэйн

Ответ 1

Цитированный ответ был неправильным. Вы должны были изменить

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

в

csvContent += dataString + "\n";

Кстати, приведенный код является неоптимальным. Вы должны избегать многократного добавления к строке. Вместо этого вы должны добавить массив, и в конце сделать 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");

Что касается того, почему цитируемый ответ был неправильным (забавно, что он был принят!): index, второй параметр функции обратного вызова forEach, является индексом в зацикленном массиве, и нет смысла сравнивать его с размером infoArray, который является элементом указанного массива (который тоже является массивом).

Ответ 2

Общая форма:

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

В вашем случае вам придется немного адаптироваться

Ответ 3

Я создал этот код для создания приятных, читаемых файлов 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, и мы помещаем значения столбца в двойные кавычки, чтобы допускать пробелы, и избегаем любых двойных кавычек в самих значениях.

Также обратите внимание, что я заменяю нулевые значения пустой строкой, потому что это соответствует моим потребностям, но вы можете изменить это и заменить его на что угодно.

Ответ 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, '');

Ответ 5

Если ваши данные содержат какие-либо символы новой строки или запятые, вам нужно будет избежать их первого:

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

Ответ 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);

Ответ 7

Выбранный ответ, вероятно, правильный, но кажется бесполезным неясным.

Я нашел Shomz Fiddle, чтобы быть очень полезным, но опять же, бесполезно неясно. (Edit: теперь я вижу, что 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));
});

Ответ 8

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