Comment lire des données à partir d'un fichier * .CSV en utilisant javascript?

199

Mes données csv ressemblent à ceci:

rubrique1, rubrique2, rubrique3, rubrique4, rubrique5, valeur1_1, valeur2_1, valeur3_1, valeur4_1, valeur5_1, valeur1_2, valeur2_2, valeur3_2, valeur4_2, valeur5_2 ....

Comment lire ces données et les convertir en un tableau comme celui-ci en utilisant Javascript?:

[rubrique1: valeur1_1, rubrique2: valeur2_1, rubrique3: valeur3_1, rubrique4: valeur4_1, rubrique5: valeur5_1], [rubrique1: valeur1_2, rubrique2: valeur2_2, rubrique3: valeur3_2, rubrique4: valeur4_2, rubrique5: valeur5_2] ....

J'ai essayé ce code mais pas de chance!:

<script type="text/javascript">
    var allText =[];
    var allTextLines = [];
    var Lines = [];

    var txtFile = new XMLHttpRequest();
    txtFile.open("GET", "file://d:/data.txt", true);
    txtFile.onreadystatechange = function()
    {
        allText = txtFile.responseText;
        allTextLines = allText.split(/\r\n|\n/);
    };

    document.write(allTextLines);<br>
    document.write(allText);<br>
    document.write(txtFile);<br>
</script>
Mahesh Thumar
la source
Sans saut de ligne dans votre fichier CSV, il sera impossible pour un code JavaScript de savoir où s'arrête un tableau (ou objet) et où commence l'autre (sauf si vous savez à l'avance qu'il y a toujours exactement cinq en-têtes). Était-ce un oubli par copier-coller?
Blazemonger
Oui, je sais à l'avance qu'il y a exactement cinq champs.
Mahesh Thumar
1
Question suivante: jQuery est-il autorisé dans la solution? Vous avez utilisé la balise, mais votre exemple de code est purement JavaScript.
Blazemonger
oui, jQuery est autorisé, c'est pourquoi je l'inclus dans Tag.
Mahesh Thumar
1
Je ne pense pas que l'utilisation de file://...soit autorisée XMLHttpRequest.
Noel Llevares

Réponses:

124

NOTE: J'ai concocté cette solution avant de me rappeler tous les "cas spéciaux" qui peuvent se produire dans un fichier CSV valide, comme les guillemets échappés. Je laisse ma réponse à ceux qui veulent quelque chose de rapide et de sale, mais je recommande la réponse d' Evan pour la précision.


Ce code fonctionnera lorsque votre data.txtfichier est une longue chaîne d'entrées séparées par des virgules, sans nouvelle ligne:

data.txt:

 heading1,heading2,heading3,heading4,heading5,value1_1,...,value5_2

javascript:

$(document).ready(function() {
    $.ajax({
        type: "GET",
        url: "data.txt",
        dataType: "text",
        success: function(data) {processData(data);}
     });
});

function processData(allText) {
    var record_num = 5;  // or however many elements there are in each row
    var allTextLines = allText.split(/\r\n|\n/);
    var entries = allTextLines[0].split(',');
    var lines = [];

    var headings = entries.splice(0,record_num);
    while (entries.length>0) {
        var tarr = [];
        for (var j=0; j<record_num; j++) {
            tarr.push(headings[j]+":"+entries.shift());
        }
        lines.push(tarr);
    }
    // alert(lines);
}

Le code suivant fonctionnera sur un "vrai" fichier CSV avec des sauts de ligne entre chaque ensemble d'enregistrements:

data.txt:

heading1,heading2,heading3,heading4,heading5
value1_1,value2_1,value3_1,value4_1,value5_1
value1_2,value2_2,value3_2,value4_2,value5_2

javascript:

$(document).ready(function() {
    $.ajax({
        type: "GET",
        url: "data.txt",
        dataType: "text",
        success: function(data) {processData(data);}
     });
});

function processData(allText) {
    var allTextLines = allText.split(/\r\n|\n/);
    var headers = allTextLines[0].split(',');
    var lines = [];

    for (var i=1; i<allTextLines.length; i++) {
        var data = allTextLines[i].split(',');
        if (data.length == headers.length) {

            var tarr = [];
            for (var j=0; j<headers.length; j++) {
                tarr.push(headers[j]+":"+data[j]);
            }
            lines.push(tarr);
        }
    }
    // alert(lines);
}

http://jsfiddle.net/mblase75/dcqxr/

Blazemonger
la source
4
En passant, cela suppose que le fichier CSV comporte en fait plusieurs lignes - c'est sur quoi allText.split(/\r\n|\n/)se divise. Si toutes vos données sont en fait une longue chaîne de données séparées par des virgules sans retour à la ligne, ce n'est pas un vrai fichier CSV.
Blazemonger
1
Salut, j'ai utilisé ce code: mais il n'y a pas de sortie. Juste une alerte vide affichée. mon fichier ressemble à: rubrique1, rubrique2, rubrique3, rubrique4, rubrique5, valeur1_1, valeur2_1, valeur3_1, valeur4_1, valeur5_1, valeur1_2, valeur2_2, valeur3_2, valeur4_2, valeur5_2 Les deux csv.html et data.txt sont dans le même dossier
Mahesh Thumar
Si ce n'est pas le bon fichier (ou les données), à quoi mon fichier devrait-il ressembler?
Mahesh Thumar
7
Le code peut ne pas gérer tous les fichiers CSV standard IETF valides et peut échouer s'il existe des chaînes contenant des virgules, des sauts de ligne ou des guillemets doubles. Par exemple, 1, "IETF allows ""quotes"", commas and \nline breaks"ce qui est autorisé car la chaîne est entourée de guillemets doubles et les guillemets doubles sont échappés.
prototype du
1
J'essayais de lire un fichier .csv à partir d'un mac. Je n'ai pu obtenir ce script pour reconnaître les caractères de nouvelle ligne que lorsque j'ai changé la première division en ceci var allTextLines = allText.split("\r"); Après cela, cela a très bien fonctionné! Merci!
Joe
211

Pas besoin d'écrire le vôtre ...

La bibliothèque jQuery-CSV a une fonction appelée $.csv.toObjects(csv)qui effectue le mappage automatiquement.

Remarque: La bibliothèque est conçue pour gérer toutes les données CSV conformes à la RFC 4180 , y compris tous les cas extrêmes que la plupart des solutions «simples» ignorent.

Comme @Blazemonger déjà indiqué, vous devez d'abord ajouter des sauts de ligne pour rendre les données valides au format CSV.

En utilisant l'ensemble de données suivant:

heading1,heading2,heading3,heading4,heading5
value1_1,value2_1,value3_1,value4_1,value5_1
value1_2,value2_2,value3_2,value4_2,value5_2

Utilisez le code:

var data = $.csv.toObjects(csv):

La sortie sauvegardée dans 'data' sera:

[
  { heading1:"value1_1",heading2:"value2_1",heading3:"value3_1",heading4:"value4_1",heading5:"value5_1" } 
  { heading1:"value1_2",heading2:"value2_2",heading3:"value3_2",heading4:"value4_2",heading5:"value5_2" }
]

Remarque: techniquement, la façon dont vous avez écrit le mappage clé-valeur n'est pas un JavaScript incorrect. Les objets contenant les paires clé-valeur doivent être placés entre crochets.

Si vous voulez l'essayer par vous-même, je vous suggère de jeter un œil à la démonstration d'utilisation de base sous l'onglet 'toObjects ()'.

Avertissement: je suis l'auteur original de jQuery-CSV.

Mise à jour:

Modifié pour utiliser l'ensemble de données fourni par l'op et inclus un lien vers la démo où les données peuvent être testées pour la validité.

Mise à jour2:

En raison de la fermeture de Google Code. jquery-csv a été déplacé vers GitHub

Plie d'Evan
la source
3
IOW, "toObject" est ou peut être considéré comme "toJSON", non? Et, est-ce que le signe deux-points suivant l'appel à toObjects (csv) est une faute de frappe? IOW, cela ne devrait-il pas être un point-virgule?
B. Clay Shannon
11
CSV est-il un nom de fichier?
bulle le
10
Fantastique bibliothèque. Pour info, le paramètre csvpassé est une chaîne csv - lisez le fichier csv sous forme de texte pour obtenir la chaîne csv.
callmekatootie
3
@Evan Plaice Comment utiliser cette librairie pour lire depuis un fichier csv?
Richa Sinha le
1
@RichaSinha Lisez le fichier en tant que tampon de texte via l'API de fichier HTML5 ou AJAX. Passez ensuite le tampon de chaîne dans l'analyseur. Cela crachera un tableau de données en conséquence. Voir la page du projet pour des exemples.
Evan Plaice
78

Ne divisez pas par des virgules - cela ne fonctionnera pas pour la plupart des fichiers CSV, et cette question a beaucoup trop de vues pour que le type de données d'entrée du demandeur s'applique à tout le monde. L'analyse CSV est un peu effrayante car il n'y a pas de norme vraiment officielle et que de nombreux rédacteurs de texte délimités ne prennent pas en compte les cas extrêmes.

Cette question est ancienne, mais je pense qu'il existe une meilleure solution maintenant que Papa Parse est disponible. C'est une bibliothèque que j'ai écrite, avec l'aide de contributeurs, qui analyse le texte ou les fichiers CSV. C'est la seule bibliothèque JS que je connaisse qui prend en charge des fichiers d'une taille de gigaoctets. Il gère également les entrées malformées avec élégance.

1 Go de fichier analysé en 1 minute: Fichier analysé de 1 Go en 1 minute

( Mise à jour: avec Papa Parse 4, le même fichier ne prenait qu'environ 30 secondes dans Firefox. Papa Parse 4 est maintenant l'analyseur CSV connu le plus rapide pour le navigateur.)

L'analyse du texte est très simple:

var data = Papa.parse(csvString);

L'analyse des fichiers est également facile:

Papa.parse(file, {
    complete: function(results) {
        console.log(results);
    }
});

Le streaming de fichiers est similaire (voici un exemple qui diffuse un fichier distant):

Papa.parse("http://example.com/bigfoo.csv", {
    download: true,
    step: function(row) {
        console.log("Row:", row.data);
    },
    complete: function() {
        console.log("All done!");
    }
});

Si votre page Web se bloque pendant l'analyse, Papa peut utiliser des travailleurs Web pour garder votre site Web réactif.

Papa peut détecter automatiquement les délimiteurs et faire correspondre les valeurs avec les colonnes d'en-tête, si une ligne d'en-tête est présente. Il peut également transformer des valeurs numériques en types de nombres réels. Il analyse de manière appropriée les sauts de ligne, les citations et autres situations étranges, et gère même les entrées malformées de manière aussi robuste que possible. Je me suis inspiré des bibliothèques existantes pour créer Papa, donc des accessoires pour d'autres implémentations JS.

Mat
la source
Papa est facile à utiliser et rapide! Merci!
Technotronic
+1 Bon travail sur Papa Parse. J'aimerais l'étudier en détail un jour pour voir comment vous avez géré les fichiers volumineux et le streaming. Je suis très heureux de voir d'autres développeurs écrire des analyseurs complets qui reprennent là où jquery-csv s'est arrêté.
Evan Plaice
3
@EvanPlaice Merci. Vous aimerez peut-être cette présentation que j'ai donnée hier soir lors d'une rencontre locale: docs.google.com/presentation/d/...
Matt
1
@ Matt C'était une présentation géniale qui décrit papa parse de manière plus compréhensive
siva
1
@ Malky.Kid Ce n'est pas un CSV valide (c'est-à-dire que les espaces dans une valeur non délimitée ne sont pas bons). L'implémentation du format CSV de MS Excel est nul. Si vous avez toujours accès au fichier source, il devrait y avoir une option pour activer les délimiteurs de devis. Une fois que vous faites cela, vos données devraient fonctionner avec n'importe quel analyseur csv.
Evan Plaice
11

J'utilise d3.js pour analyser le fichier csv. Utilisation très simple. Voici la documentation .

Pas:

  • npm installer d3-request

Utilisation de Es6;

import { csv } from 'd3-request';
import url from 'path/to/data.csv';

csv(url, function(err, data) {
 console.log(data);
})

Veuillez consulter la documentation pour en savoir plus.

Mise à jour - d3-request est obsolète. vous pouvez utiliser d3-fetch

Bimal Grg
la source
4

Voici une fonction JavaScript qui analyse les données CSV, en tenant compte des virgules trouvées entre guillemets.

// Parse a CSV row, accounting for commas inside quotes                   
function parse(row){
  var insideQuote = false,                                             
      entries = [],                                                    
      entry = [];
  row.split('').forEach(function (character) {                         
    if(character === '"') {
      insideQuote = !insideQuote;                                      
    } else {
      if(character == "," && !insideQuote) {                           
        entries.push(entry.join(''));                                  
        entry = [];                                                    
      } else {
        entry.push(character);                                         
      }                                                                
    }                                                                  
  });
  entries.push(entry.join(''));                                        
  return entries;                                                      
}

Exemple d'utilisation de la fonction pour analyser un fichier CSV qui ressemble à ceci:

"foo, the column",bar
2,3
"4, the value",5

en tableaux:

// csv could contain the content read from a csv file
var csv = '"foo, the column",bar\n2,3\n"4, the value",5',

    // Split the input into lines
    lines = csv.split('\n'),

    // Extract column names from the first line
    columnNamesLine = lines[0],
    columnNames = parse(columnNamesLine),

    // Extract data from subsequent lines
    dataLines = lines.slice(1),
    data = dataLines.map(parse);

// Prints ["foo, the column","bar"]
console.log(JSON.stringify(columnNames));

// Prints [["2","3"],["4, the value","5"]]
console.log(JSON.stringify(data));

Voici comment vous pouvez transformer les données en objets, comme l'analyseur csv de D3 (qui est une solution tierce solide):

var dataObjects = data.map(function (arr) {
  var dataObject = {};
  columnNames.forEach(function(columnName, i){
    dataObject[columnName] = arr[i];
  });
  return dataObject;
});

// Prints [{"foo":"2","bar":"3"},{"foo":"4","bar":"5"}]
console.log(JSON.stringify(dataObjects));

Voici un violon fonctionnel de ce code .

Prendre plaisir! - Curran

Curran
la source
4

Vous pouvez utiliser PapaParse pour vous aider. https://www.papaparse.com/

Voici un CodePen. https://codepen.io/sandro-wiggers/pen/VxrxNJ

Papa.parse(e, {
            header:true,
            before: function(file, inputElem){ console.log('Attempting to Parse...')},
            error: function(err, file, inputElem, reason){ console.log(err); },
            complete: function(results, file){ $.PAYLOAD = results; }
        });
Sandro Wiggers
la source
1

Voici une autre façon de lire un CSV externe en Javascript (en utilisant jQuery).

C'est un peu plus long, mais je pense qu'en lisant les données dans des tableaux, vous pouvez suivre exactement le processus et faciliter le dépannage.

Pourrait aider quelqu'un d'autre.

L'exemple de fichier de données:

Time,data1,data2,data2
08/11/2015 07:30:16,602,0.009,321

Et voici le code:

$(document).ready(function() {
 // AJAX in the data file
    $.ajax({
        type: "GET",
        url: "data.csv",
        dataType: "text",
        success: function(data) {processData(data);}
        });

    // Let's process the data from the data file
    function processData(data) {
        var lines = data.split(/\r\n|\n/);

        //Set up the data arrays
        var time = [];
        var data1 = [];
        var data2 = [];
        var data3 = [];

        var headings = lines[0].split(','); // Splice up the first row to get the headings

        for (var j=1; j<lines.length; j++) {
        var values = lines[j].split(','); // Split up the comma seperated values
           // We read the key,1st, 2nd and 3rd rows 
           time.push(values[0]); // Read in as string
           // Recommended to read in as float, since we'll be doing some operations on this later.
           data1.push(parseFloat(values[1])); 
           data2.push(parseFloat(values[2]));
           data3.push(parseFloat(values[3]));

        }

    // For display
    var x= 0;
    console.log(headings[0]+" : "+time[x]+headings[1]+" : "+data1[x]+headings[2]+" : "+data2[x]+headings[4]+" : "+data2[x]);
    }
})

J'espère que cela aidera quelqu'un à l'avenir!

FredFury
la source
Bonjour du futur, j'ai donc essayé cette réponse et il manquait un )signe à la ligne 45, alors je l'ai ajouté, mais maintenant à la ligne 9, cela me donne une erreur de console. Uncaught ReferenceError: $ is not defined at index.html:9Pourriez-vous aider?
Lasagna Cat
1
function CSVParse(csvFile)
{
    this.rows = [];

    var fieldRegEx = new RegExp('(?:\s*"((?:""|[^"])*)"\s*|\s*((?:""|[^",\r\n])*(?:""|[^"\s,\r\n]))?\s*)(,|[\r\n]+|$)', "g");   
    var row = [];
    var currMatch = null;

    while (currMatch = fieldRegEx.exec(this.csvFile))
    {
        row.push([currMatch[1], currMatch[2]].join('')); // concatenate with potential nulls

        if (currMatch[3] != ',')
        {
            this.rows.push(row);
            row = [];
        }

        if (currMatch[3].length == 0)
            break;
    }
}

J'aime que le regex fasse autant que possible. Cette expression régulière traite tous les éléments comme étant entre guillemets ou non, suivis soit d'un délimiteur de colonne, soit d'un délimiteur de ligne. Ou la fin du texte.

C'est pourquoi cette dernière condition - sans elle, ce serait une boucle infinie puisque le motif peut correspondre à un champ de longueur nulle (totalement valide en csv). Mais puisque $ est une assertion de longueur nulle, elle ne progressera pas vers une non-correspondance et ne terminera pas la boucle.

Et pour info, j'ai dû faire la deuxième alternative exclure les citations entourant la valeur; semble s'exécuter avant la première alternative sur mon moteur javascript et considérant les guillemets comme faisant partie de la valeur non citée. Je ne vais pas demander - juste le faire fonctionner.

Gérard ONeill
la source
Malheureusement, je suis entré dans une boucle infinie avec cette fonction.
Hauke
@Hauke ​​- si vous pouviez diviser les données en quelques colonnes et lignes qui produisent toujours la boucle infinie, je l'apprécierais - cela peut me donner un aperçu des raisons pour lesquelles j'ai échoué auparavant.
Gerard ONeill
1

Par la réponse acceptée ,

J'ai fait fonctionner cela en changeant le 1 en 0 ici:

for (var i=1; i<allTextLines.length; i++) {

changé en

for (var i=0; i<allTextLines.length; i++) {

Il calculera le fichier a avec une ligne continue comme ayant un allTextLines.length de 1. Donc, si la boucle commence à 1 et s'exécute tant qu'elle est inférieure à 1, elle ne s'exécute jamais. D'où la boîte d'alerte vide.

Adam Grant
la source
1

Si vous souhaitez résoudre ce problème sans utiliser Ajax , utilisez l' FileReader()API Web .

Exemple d'implémentation:

  1. Sélectionnez un .csvfichier
  2. Voir la sortie

function readSingleFile(e) {
  var file = e.target.files[0];
  if (!file) {
    return;
  }

  var reader = new FileReader();
  reader.onload = function(e) {
    var contents = e.target.result;
    displayContents(contents);
    displayParsed(contents);
  };
  reader.readAsText(file);
}

function displayContents(contents) {
  var element = document.getElementById('file-content');
  element.textContent = contents;
}

function displayParsed(contents) {
  const element = document.getElementById('file-parsed');
  const json = contents.split(',');
  element.textContent = JSON.stringify(json);
}

document.getElementById('file-input').addEventListener('change', readSingleFile, false);
<input type="file" id="file-input" />

<h3>Raw contents of the file:</h3>
<pre id="file-content">No data yet.</pre>

<h3>Parsed file contents:</h3>
<pre id="file-parsed">No data yet.</pre>

Robin Rpr.
la source
1

Un peu tard mais j'espère que ça aide quelqu'un.

Il y a quelque temps, même j'ai été confronté à un problème où les données de chaîne contenues \nentre et lors de la lecture du fichier qu'il lisait étaient des lignes différentes.

Par exemple.

"Harry\nPotter","21","Gryffindor"

En lisant:

Harry
Potter,21,Gryffindor

J'avais utilisé une bibliothèque csvtojson dans mon projet angulaire pour résoudre ce problème.

Vous pouvez lire le fichier CSV sous forme de chaîne à l'aide du code suivant, puis transmettre cette chaîne à la bibliothèque csvtojson et elle vous donnera une liste de JSON.

Exemple de code:

const csv = require('csvtojson');
if (files && files.length > 0) {
    const file: File = files.item(0);
    const reader: FileReader = new FileReader();
    reader.readAsText(file);
    reader.onload = (e) => {
    const csvs: string = reader.result as string;
    csv({
        output: "json",
        noheader: false
    }).fromString(csvs)
        .preFileLine((fileLine, idx) => {
        //Convert csv header row to lowercase before parse csv file to json
        if (idx === 0) { return fileLine.toLowerCase() }
        return fileLine;
        })
        .then((result) => {
        // list of json in result
        });
    }
}
bhavya_karia
la source
0
$(function() {

      $("#upload").bind("click", function() {
            var regex = /^([a-zA-Z0-9\s_\\.\-:])+(.csv|.xlsx)$/;
            if (regex.test($("#fileUpload").val().toLowerCase())) {
              if (typeof(FileReader) != "undefined") {
                var reader = new FileReader();
                reader.onload = function(e) {
                    var customers = new Array();
                    var rows = e.target.result.split("\r\n");
                    for (var i = 0; i < rows.length - 1; i++) {
                      var cells = rows[i].split(",");
                      if (cells[0] == "" || cells[0] == undefined) {
                        var s = customers[customers.length - 1];
                        s.Ord.push(cells[2]);
                      } else {
                        var dt = customers.find(x => x.Number === cells[0]);
                        if (dt == undefined) {
                          if (cells.length > 1) {
                            var customer = {};
                            customer.Number = cells[0];
                            customer.Name = cells[1];
                            customer.Ord = new Array();

                            customer.Ord.push(cells[2]);
                            customer.Point_ID = cells[3];
                            customer.Point_Name = cells[4];
                            customer.Point_Type = cells[5];
                            customer.Set_ORD = cells[6];
                            customers.push(customer);
                          }
                        } else {
                          var dtt = dt;
                          dtt.Ord.push(cells[2]);

                        }
                      }
                    }
rahul kulkarni
la source
Bien que ce code puisse résoudre la question, inclure une explication sur comment et pourquoi cela résout le problème aiderait vraiment à améliorer la qualité de votre publication et entraînerait probablement plus de votes à la hausse. N'oubliez pas que vous répondez à la question des lecteurs à l'avenir, pas seulement à la personne qui la pose maintenant. Veuillez modifier votre réponse pour ajouter des explications et donner une indication des limites et des hypothèses applicables. De l'avis
double-beep
0

En fait, vous pouvez utiliser une bibliothèque légère appelée any-text .

  • installer les dépendances
npm i -D any-text
  • utiliser une commande personnalisée pour lire les fichiers
var reader = require('any-text');
 
reader.getText(`path-to-file`).then(function (data) {
  console.log(data);
});

ou utilisez async-await:

var reader = require('any-text');
 
const chai = require('chai');
const expect = chai.expect;
 
describe('file reader checks', () => {
  it('check csv file content', async () => {
    expect(
      await reader.getText(`${process.cwd()}/test/files/dummy.csv`)
    ).to.contains('Lorem ipsum');
  });
});
Abhinaba
la source
Vous n'avez pas besoin npmde tout
Dinosaures mortels