Código Javascript para analisar dados CSV


215

Alguém tem uma idéia de onde eu poderia encontrar algum código javascript para analisar dados CSV?


3
Dê uma olhada nesta resposta aqui, ele tem boas respostas: stackoverflow.com/questions/8493195/...
Dobes Vandermeer

14
A maioria das respostas abaixo estão erradas, além da de Andy. Qualquer resposta que use correspondência ou divisão de padrões está fadada ao fracasso - elas não suportam seqüências de escape. Para isso, você precisa de uma máquina de estados finitos.
greg.kindel

3
Analisando um arquivo CSV local com JavaScript e Papa Parse: joyofdata.de/blog/…
Raffael

4
Papa Parse é outra opção com um monte de recursos (multi-threaded, suporte linha de cabeçalho, auto-detectar delimitador, e mais)
Hinrich

1
Outro voto para o PapaParse, estou usando com o AngularJS e funciona muito bem.
Dmitry Buslaev

Respostas:


257

Você pode usar a função CSVToArray () mencionada nesta entrada do blog.

<script type="text/javascript">
    // ref: http://stackoverflow.com/a/1293163/2343
    // This will parse a delimited string into an array of
    // arrays. The default delimiter is the comma, but this
    // can be overriden in the second argument.
    function CSVToArray( strData, strDelimiter ){
        // Check to see if the delimiter is defined. If not,
        // then default to comma.
        strDelimiter = (strDelimiter || ",");

        // Create a regular expression to parse the CSV values.
        var objPattern = new RegExp(
            (
                // Delimiters.
                "(\\" + strDelimiter + "|\\r?\\n|\\r|^)" +

                // Quoted fields.
                "(?:\"([^\"]*(?:\"\"[^\"]*)*)\"|" +

                // Standard fields.
                "([^\"\\" + strDelimiter + "\\r\\n]*))"
            ),
            "gi"
            );


        // Create an array to hold our data. Give the array
        // a default empty first row.
        var arrData = [[]];

        // Create an array to hold our individual pattern
        // matching groups.
        var arrMatches = null;


        // Keep looping over the regular expression matches
        // until we can no longer find a match.
        while (arrMatches = objPattern.exec( strData )){

            // Get the delimiter that was found.
            var strMatchedDelimiter = arrMatches[ 1 ];

            // Check to see if the given delimiter has a length
            // (is not the start of string) and if it matches
            // field delimiter. If id does not, then we know
            // that this delimiter is a row delimiter.
            if (
                strMatchedDelimiter.length &&
                strMatchedDelimiter !== strDelimiter
                ){

                // Since we have reached a new row of data,
                // add an empty row to our data array.
                arrData.push( [] );

            }

            var strMatchedValue;

            // Now that we have our delimiter out of the way,
            // let's check to see which kind of value we
            // captured (quoted or unquoted).
            if (arrMatches[ 2 ]){

                // We found a quoted value. When we capture
                // this value, unescape any double quotes.
                strMatchedValue = arrMatches[ 2 ].replace(
                    new RegExp( "\"\"", "g" ),
                    "\""
                    );

            } else {

                // We found a non-quoted value.
                strMatchedValue = arrMatches[ 3 ];

            }


            // Now that we have our value string, let's add
            // it to the data array.
            arrData[ arrData.length - 1 ].push( strMatchedValue );
        }

        // Return the parsed data.
        return( arrData );
    }

</script>

1
Ele pode lidar com vírgulas, aspas e quebras de linha incorporadas, por exemplo: var csv = 'id, valor \ n1, James \ n02, "Jimmy Smith, Esq." \ N003, "James" "Jimmy" "Smith, III" \ n0004, "James \ nSmith \ nWuz Here" 'var array = CSVToArray (csv, ",");
Protótipo

4
undefinedpara campos vazios que são citados . Exemplo: CSVToArray("4,,6")me dá [["4","","6"]], mas CSVToArray("4,\"\",6")me dá [["4",undefined,"6"]].
Pang

3
Eu tive problemas com isso no firefox, e o script ficou sem resposta. Ele parecia afetar apenas alguns usuários, porém, assim não poderia encontrar a causa
JDandChips

8
Há um erro no regex: "([^\"\\"deveria ser "([^\\". Caso contrário, uma citação dupla em qualquer lugar com um valor não citado terminará prematuramente. Encontrado isso da maneira mais difícil ...
Walter Tross

5
Para quem procura uma versão reduzida do método acima, com a correção regex descrito acima aplicados: gist.github.com/Jezternz/c8e9fafc2c114e079829974e3764db75
Josh Mc

147

jQuery-CSV

É um plugin jquery projetado para funcionar como uma solução completa para analisar CSV em dados Javascript. Ele lida com todos os casos de borda apresentados no RFC 4180 , bem como com alguns que surgem para exportações do Excel / Google Spreadsheed (ou seja, principalmente envolvendo valores nulos) que estão faltando nas especificações.

Exemplo:

faixa, artista, álbum, ano

Dangerous, 'Busta Rhymes', 'When Disaster Strikes', 1997

// calling this
music = $.csv.toArrays(csv)

// outputs...
[
  ["track","artist","album","year"],
  ["Dangerous","Busta Rhymes","When Disaster Strikes","1997"]
]

console.log(music[1][2]) // outputs: 'When Disaster Strikes'

Atualizar:

Ah, sim, eu também deveria mencionar que é completamente configurável.

music = $.csv.toArrays(csv, {
  delimiter:"'", // sets a custom value delimiter character
  separator:';', // sets a custom field separator character
});

Atualização 2:

Agora ele também funciona com o jQuery no Node.js. Portanto, você tem a opção de analisar do lado do cliente ou do servidor com a mesma lib.

Atualização 3:

Desde o desligamento do Google Code, o jquery-csv foi migrado para o GitHub .

Isenção de responsabilidade: Eu também sou o autor do jQuery-CSV.


29
Por que é jQuery csv? Por que isso depende do jQuery? Eu tive uma verificação rápida através da fonte ... não parecer que você está usando jQuery
paulslater19

17
@ paulslater19 O plugin não depende do jquery. Em vez disso, segue as diretrizes comuns de desenvolvimento do jQuery. Todos os métodos incluídos são estáticos e residem em seu próprio espaço para nome (por exemplo, $ .csv). Para usá-los sem o jQuery, basta criar um objeto $ global ao qual o plug-in se ligará durante a inicialização.
Evan Solha

2
está csvno código da solução, consulte o .csv filename? Estou interessado em uma boa ferramenta JS / JQuery para analisar um arquivo CSV
bouncingHippo

1
@bouncingHippo No exemplo, está apenas se referindo a uma sequência de dados csv, mas a lib pode ser usada para abrir arquivos csv localmente no navegador usando a API de arquivos HTML5. Aqui está um exemplo disso na ação jquery-csv.googlecode.com/git/examples/file-handling.html .
Evan Solha

1
Como não é dependente do jQuery, seria melhor remover a dependência global "$" e permitir que os usuários passassem qualquer referência a objeto que desejassem. Talvez o padrão seja o jQuery, se estiver disponível. Existem outras bibliotecas que usam "$" e podem ser usadas pelas equipes de desenvolvimento com proxies mínimos dessas bibliotecas.
RobG

40

Eu tenho uma implementação como parte de um projeto de planilha.

Esse código ainda não foi testado completamente, mas qualquer pessoa pode usá-lo.

Como algumas das respostas observadas, porém, sua implementação pode ser muito mais simples se você realmente tiver um arquivo DSV ou TSV , pois eles não permitem o uso dos separadores de registro e campo nos valores. O CSV, por outro lado, pode realmente ter vírgulas e novas linhas dentro de um campo, o que quebra a maioria das abordagens regex e baseadas em divisão.

var CSV = {
parse: function(csv, reviver) {
    reviver = reviver || function(r, c, v) { return v; };
    var chars = csv.split(''), c = 0, cc = chars.length, start, end, table = [], row;
    while (c < cc) {
        table.push(row = []);
        while (c < cc && '\r' !== chars[c] && '\n' !== chars[c]) {
            start = end = c;
            if ('"' === chars[c]){
                start = end = ++c;
                while (c < cc) {
                    if ('"' === chars[c]) {
                        if ('"' !== chars[c+1]) { break; }
                        else { chars[++c] = ''; } // unescape ""
                    }
                    end = ++c;
                }
                if ('"' === chars[c]) { ++c; }
                while (c < cc && '\r' !== chars[c] && '\n' !== chars[c] && ',' !== chars[c]) { ++c; }
            } else {
                while (c < cc && '\r' !== chars[c] && '\n' !== chars[c] && ',' !== chars[c]) { end = ++c; }
            }
            row.push(reviver(table.length-1, row.length, chars.slice(start, end).join('')));
            if (',' === chars[c]) { ++c; }
        }
        if ('\r' === chars[c]) { ++c; }
        if ('\n' === chars[c]) { ++c; }
    }
    return table;
},

stringify: function(table, replacer) {
    replacer = replacer || function(r, c, v) { return v; };
    var csv = '', c, cc, r, rr = table.length, cell;
    for (r = 0; r < rr; ++r) {
        if (r) { csv += '\r\n'; }
        for (c = 0, cc = table[r].length; c < cc; ++c) {
            if (c) { csv += ','; }
            cell = replacer(r, c, table[r][c]);
            if (/[,\r\n"]/.test(cell)) { cell = '"' + cell.replace(/"/g, '""') + '"'; }
            csv += (cell || 0 === cell) ? cell : '';
        }
    }
    return csv;
}
};

9
Esta é uma das minhas respostas favoritas. É um analisador real implementado em pouco código.
Trevor Dixon

1
Se uma vírgula for colocada no final de uma linha, uma célula vazia deverá segui-la. Esse código apenas pula para a próxima linha, resultando em uma undefinedcélula. Por exemplo,console.log(CSV.parse("first,last,age\r\njohn,doe,"));
skibulk

Além disso, as células vazias devem analisar cadeias vazias. Este código analisa-os em zeros, que é confuso desde células pode realmente conter zeros:console.log(CSV.parse("0,,2,3"));
skibulk

@skibulk Seu segundo comentário está incorreto (pelo menos no Chrome funciona bem com o seu exemplo). Seu primeiro comentário é válido, embora seja facilmente corrigido - adicione o seguinte antes if ('\r' === chars[c]) { ... }:if (end === c-1) { row.push(reviver(table.length-1, row.length, '')); }
coderforlife 7/16

35

Aqui está um analisador CSV extremamente simples que lida com campos entre vírgulas, novas linhas e aspas duplas com escape. Não há divisão ou RegEx. Ele verifica a cadeia de entrada com 1-2 caracteres por vez e cria uma matriz.

Teste-o em http://jsfiddle.net/vHKYH/ .

function parseCSV(str) {
    var arr = [];
    var quote = false;  // true means we're inside a quoted field

    // iterate over each character, keep track of current row and column (of the returned array)
    for (var row = 0, col = 0, c = 0; c < str.length; c++) {
        var cc = str[c], nc = str[c+1];        // current character, next character
        arr[row] = arr[row] || [];             // create a new row if necessary
        arr[row][col] = arr[row][col] || '';   // create a new column (start with empty string) if necessary

        // If the current character is a quotation mark, and we're inside a
        // quoted field, and the next character is also a quotation mark,
        // add a quotation mark to the current column and skip the next character
        if (cc == '"' && quote && nc == '"') { arr[row][col] += cc; ++c; continue; }  

        // If it's just one quotation mark, begin/end quoted field
        if (cc == '"') { quote = !quote; continue; }

        // If it's a comma and we're not in a quoted field, move on to the next column
        if (cc == ',' && !quote) { ++col; continue; }

        // If it's a newline (CRLF) and we're not in a quoted field, skip the next character
        // and move on to the next row and move to column 0 of that new row
        if (cc == '\r' && nc == '\n' && !quote) { ++row; col = 0; ++c; continue; }

        // If it's a newline (LF or CR) and we're not in a quoted field,
        // move on to the next row and move to column 0 of that new row
        if (cc == '\n' && !quote) { ++row; col = 0; continue; }
        if (cc == '\r' && !quote) { ++row; col = 0; continue; }

        // Otherwise, append the current character to the current column
        arr[row][col] += cc;
    }
    return arr;
}

É simples e funciona para mim, a única coisa que mudou foi a adição de uma guarnição () para o valor :)
JustEngland

3
Isso parece mais limpo e direto. Eu tive que analisar um arquivo de 4mb e as outras respostas bateram em mim no ie8, mas isso conseguiu.
Charles Clayton

3
Isso também funcionou para mim. Eu tive que fazer uma modificação no entanto para permitir tratamento adequado dos avanços de linha:if (cc == '\r' && nc == '\n' && !quote) { ++row; col = 0; ++c; continue; } if (cc == '\n' && !quote) { ++row; col = 0; continue; }
user655063

1
Outro usuário (@ sorin-postelnicu) publicou uma função complementar para transformar o resultado em um objeto de dicionário: jsfiddle.net/8t2po6wh .
Trevor Dixon

1
Sim, sempre que a velocidade é necessária ou a pegada da memória importa, uma solução limpa como essa é muito superior. A análise de esquemas de máquina do estado é muito mais suave.
Tatarize 9/08/19

14

Aqui está minha gramática PEG (.js) que parece funcionar bem na RFC 4180 (ou seja, lida com os exemplos em http://en.wikipedia.org/wiki/Comma-separated_values ):

start
  = [\n\r]* first:line rest:([\n\r]+ data:line { return data; })* [\n\r]* { rest.unshift(first); return rest; }

line
  = first:field rest:("," text:field { return text; })*
    & { return !!first || rest.length; } // ignore blank lines
    { rest.unshift(first); return rest; }

field
  = '"' text:char* '"' { return text.join(''); }
  / text:[^\n\r,]* { return text.join(''); }

char
  = '"' '"' { return '"'; }
  / [^"]

Experimente em http://jsfiddle.net/knvzk/10 ou http://pegjs.majda.cz/online . Faça o download do analisador gerado em https://gist.github.com/3362830 .


2
PEG? Não está construindo um AST com pouca memória para uma gramática do Tipo III. Ele pode manipular campos que contêm caracteres de nova linha, porque esse é o caso mais difícil de abordar em um analisador de 'gramática regular'. De qualquer forma, +1 para uma nova abordagem.
Evan Solha

1
Sim, ele lida com nova linha dentro de um campo.
Trevor Dixon

2
Bom ... Só isso, é melhor do que 95% de todas as implementações que eu já vi. Se você deseja verificar a conformidade total com RFC, consulte os testes aqui ( jquery-csv.googlecode.com/git/test/test.html ).
Evan Plaice

6
Bem jogado. +1 por ativar o PEG. Eu amo geradores de analisadores. "Por que programar manualmente em cinco dias o que você pode passar cinco anos de sua vida automatizando?" - Terence Parr, ANTLR
Subfuzion 28/03

14

csvToArray v1.3

Uma função compacta (645 bytes), mas compatível, para converter uma sequência CSV em uma matriz 2D, em conformidade com o padrão RFC4180.

https://code.google.com/archive/p/csv-to-array/downloads

Uso comum: jQuery

 $.ajax({
        url: "test.csv",
        dataType: 'text',
        cache: false
 }).done(function(csvAsString){
        csvAsArray=csvAsString.csvToArray();
 });

Uso comum: Javascript

csvAsArray = csvAsString.csvToArray();

Substituir separador de campos

csvAsArray = csvAsString.csvToArray("|");

Substituir separador de registros

csvAsArray = csvAsString.csvToArray("", "#");

Substituir Ignorar Cabeçalho

csvAsArray = csvAsString.csvToArray("", "", 1);

Substituir tudo

csvAsArray = csvAsString.csvToArray("|", "#", 1);

Parece interessante, mas não consigo encontrar o código agora. Você pode publicá-lo novamente?
Sam Watkins

1
Atualizei a postagem principal com um link atual. Muito Obrigado.
dt192

3

Não sei por que não pude kirtans ex. trabalhar para mim. Parecia estar falhando em campos vazios ou talvez campos com vírgulas à direita ...

Este parece lidar com ambos.

Não escrevi o código do analisador, apenas um invólucro em torno da função do analisador para fazer esse trabalho para um arquivo. veja Atribuição

    var Strings = {
        /**
         * Wrapped csv line parser
         * @param s string delimited csv string
         * @param sep separator override
         * @attribution : http://www.greywyvern.com/?post=258 (comments closed on blog :( )
         */
        parseCSV : function(s,sep) {
            // http://stackoverflow.com/questions/1155678/javascript-string-newline-character
            var universalNewline = /\r\n|\r|\n/g;
            var a = s.split(universalNewline);
            for(var i in a){
                for (var f = a[i].split(sep = sep || ","), x = f.length - 1, tl; x >= 0; x--) {
                    if (f[x].replace(/"\s+$/, '"').charAt(f[x].length - 1) == '"') {
                        if ((tl = f[x].replace(/^\s+"/, '"')).length > 1 && tl.charAt(0) == '"') {
                            f[x] = f[x].replace(/^\s*"|"\s*$/g, '').replace(/""/g, '"');
                          } else if (x) {
                        f.splice(x - 1, 2, [f[x - 1], f[x]].join(sep));
                      } else f = f.shift().split(sep).concat(f);
                    } else f[x].replace(/""/g, '"');
                  } a[i] = f;
        }
        return a;
        }
    }

1

Expressões regulares para o resgate! Essas poucas linhas de código manipulam campos citados corretamente com vírgulas, aspas e novas linhas incorporadas, com base no padrão RFC 4180.

function parseCsv(data, fieldSep, newLine) {
    fieldSep = fieldSep || ',';
    newLine = newLine || '\n';
    var nSep = '\x1D';
    var qSep = '\x1E';
    var cSep = '\x1F';
    var nSepRe = new RegExp(nSep, 'g');
    var qSepRe = new RegExp(qSep, 'g');
    var cSepRe = new RegExp(cSep, 'g');
    var fieldRe = new RegExp('(?<=(^|[' + fieldSep + '\\n]))"(|[\\s\\S]+?(?<![^"]"))"(?=($|[' + fieldSep + '\\n]))', 'g');
    var grid = [];
    data.replace(/\r/g, '').replace(/\n+$/, '').replace(fieldRe, function(match, p1, p2) {
        return p2.replace(/\n/g, nSep).replace(/""/g, qSep).replace(/,/g, cSep);
    }).split(/\n/).forEach(function(line) {
        var row = line.split(fieldSep).map(function(cell) {
            return cell.replace(nSepRe, newLine).replace(qSepRe, '"').replace(cSepRe, ',');
        });
        grid.push(row);
    });
    return grid;
}

const csv = 'A1,B1,C1\n"A ""2""","B, 2","C\n2"';
const separator = ',';      // field separator, default: ','
const newline = ' <br /> '; // newline representation in case a field contains newlines, default: '\n' 
var grid = parseCsv(csv, separator, newline);
// expected: [ [ 'A1', 'B1', 'C1' ], [ 'A "2"', 'B, 2', 'C <br /> 2' ] ]

Você não precisa de um gerador de analisador como lex / yacc. A expressão regular lida com o RFC 4180 corretamente, graças a aparência positiva, aparência negativa e aparência positiva.

Clone / faça o download do código em https://github.com/peterthoeny/parse-csv-js


Os regexps são implementados usando máquinas de estados finitos, portanto, você realmente precisa do FSM.
Henry Henrinson

@HenryHenrinson: Não necessariamente. Desafio você a encontrar um problema com o código acima. Eu uso na produção. Também é possível fazer uma análise mais complexa com expressões regulares. Você não precisa de um analisador LL para criar uma árvore de sintaxe. Aqui está um blog: Como usar expressões regulares para analisar estruturas aninhadas, twiki.org/cgi-bin/view/Blog/BlogEntry201109x3
Peter Thoeny

@HenryHenrinson: Ah, sim, me engane, estamos em um acordo violento :-)
Peter Thoeny

-1

Eu construí este script javascript para analisar um CSV em seqüência de caracteres para o objeto de matriz. Acho melhor dividir todo o CSV em linhas, campos e processá-los de acordo. Eu acho que facilitará a alteração do código para atender às suas necessidades.

Espero que ajude você. Obrigado.

    //
    //
    // CSV to object
    //
    //

    const new_line_char = '\n';
    const field_separator_char = ',';

    function parse_csv(csv_str) {

        var result = [];

        let line_end_index_moved = false;
        let line_start_index = 0;
        let line_end_index = 0;
        let csr_index = 0;
        let cursor_val = csv_str[csr_index];
        let found_new_line_char = get_new_line_char(csv_str);
        let in_quote = false;

        // handle \r\n
        if (found_new_line_char == '\r\n') {
            csv_str = csv_str.split(found_new_line_char).join(new_line_char);
        }
        // handle last char is not \n
        if (csv_str[csv_str.length - 1] !== new_line_char) {
            csv_str += new_line_char;
        }

        while (csr_index < csv_str.length) {
            if (cursor_val === '"') {
                in_quote = !in_quote;
            } else if (cursor_val === new_line_char) {
                if (in_quote === false) {
                    if (line_end_index_moved && (line_start_index <= line_end_index)) {
                        result.push(parse_csv_line(csv_str.substring(line_start_index, line_end_index)));
                        line_start_index = csr_index + 1;
                    } // else: just ignore line_end_index has not moved or line has not been sliced for parsing the line
                } // else: just ignore because we are in quote
            }
            csr_index++;
            cursor_val = csv_str[csr_index];
            line_end_index = csr_index;
            line_end_index_moved = true;
        }

        // handle \r\n
        if (found_new_line_char == '\r\n') {
            let new_result = [];
            let curr_row;
            for (var i = 0; i < result.length; i++) {
                curr_row = [];
                for (var j = 0; j < result[i].length; j++) {
                    curr_row.push(result[i][j].split(new_line_char).join('\r\n'));
                }
                new_result.push(curr_row);
            }
            result = new_result;
        }

        return result;
    }

    function parse_csv_line(csv_line_str) {

        var result = [];

        // let field_end_index_moved = false;
        let field_start_index = 0;
        let field_end_index = 0;
        let csr_index = 0;
        let cursor_val = csv_line_str[csr_index];
        let in_quote = false;

        // Pretend that the last char is the separator_char to complete the loop
        csv_line_str += field_separator_char;

        while (csr_index < csv_line_str.length) {
            if (cursor_val === '"') {
                in_quote = !in_quote;
            } else if (cursor_val === field_separator_char) {
                if (in_quote === false) {
                    if (field_start_index <= field_end_index) {
                        result.push(parse_csv_field(csv_line_str.substring(field_start_index, field_end_index)));
                        field_start_index = csr_index + 1;
                    } // else: just ignore field_end_index has not moved or field has not been sliced for parsing the field
                } // else: just ignore because we are in quote
            }
            csr_index++;
            cursor_val = csv_line_str[csr_index];
            field_end_index = csr_index;
            field_end_index_moved = true;
        }

        return result;
    }

    function parse_csv_field(csv_field_str) {
        with_quote = (csv_field_str[0] === '"');

        if (with_quote) {
            csv_field_str = csv_field_str.substring(1, csv_field_str.length - 1); // remove the start and end quotes
            csv_field_str = csv_field_str.split('""').join('"'); // handle double quotes
        }

        return csv_field_str;
    }

    // initial method: check the first newline character only
    function get_new_line_char(csv_str) {
        if (csv_str.indexOf('\r\n') > -1) {
            return '\r\n';
        } else {
            return '\n'
        }
    }

-3

Por que não usar apenas .split (',')?

http://www.w3schools.com/jsref/jsref_split.asp

var str="How are you doing today?";
var n=str.split(" "); 

2
Por que essa é uma resposta ruim? É nativo, coloca o conteúdo da string em um array viável ...
Micah

20
Muitas razões. Primeiro, ele não remove as aspas duplas nos valores delimitados. Não lida com divisão de linhas. Não escapa aspas duplas usadas para escapar de aspas duplas usadas em valores delimitados. Não permite valores vazios. etc, etc ... A flexibilidade do formato CSV torna muito fácil de usar, mas difícil de analisar. Não vou diminuir o voto, mas apenas porque não diminuo as respostas concorrentes.
quer

1
E quando você encontra um valor que contém um caractere de nova linha? Uma função de divisão simples a interpretará incorretamente como o final de uma entrada, em vez de pular sobre ela como deveria. A análise de CSV é muito mais complicada do que apenas fornecer duas rotinas divididas (uma para novas linhas e outra para delimitadores).
quer

2
(cont) Também dividido em valores nulos (a, null ,, value) não retorna nada, mas deve retornar uma string vazia. Não me interpretem mal, a divisão é um bom começo se você é 100% positivo de que os dados recebidos não quebram o analisador, mas a criação de um analisador robusto que pode lidar com todos os dados compatíveis com RFC 4801 é significativamente mais complicada.
quer

8
Evan, acho que sua biblioteca javascript é incrível. Mas aqui está outra perspectiva: eu apreciei essa resposta, pois estou simplesmente armazenando uma série de números de uma maneira muito previsível. É muito mais importante para mim obter a compatibilidade e a manutenção garantidas de Javascript entre navegadores o mais longe possível no futuro, do que incluir uma biblioteca grande (embora bem escrita e bem testada). Necessidades diferentes requerem abordagens diferentes. Se eu precisar de um verdadeiro poder CSV, DEFINITIVAMENTE, comprometo-me a usar sua biblioteca! :-)
moodboom 20/02
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.