Manipulation de fichiers CSV en JavaScript Vanilla
Il m'arrive régulièrement de manipuler des fichiers CSV en JavaScript. Pour mes besoins assez limité, j'aime bien réutiliser des petits bouts de code que je vais partager ici.
Pour manipuler du JavaScript dans un projet important, il peut être plus prudent d'utiliser une librairie du type Papa Parse.
J'utilise donc un fichier avec des fonctions relativement simples :
Fichier : csvUtilities.js (js)1function splitByObject(csv) { 2 const lines = []; 3 let current = ''; 4 let inQuotes = false; 5 6 for (let i = 0; i < csv.length; i++) { 7 const char = csv[i]; 8 9 if (char === '"') { 10 // gérer """" 11 const next = csv[i + 1]; 12 if (inQuotes && next === '"') { 13 current += '"'; 14 i++; 15 } else { 16 inQuotes = !inQuotes; 17 } 18 current += char; 19 } 20 else if ((char === '\n' || char === '\r') && !inQuotes) { 21 // FIN DE LIGNE — si on n’est pas dans les guillemets 22 if (current.trim() !== '') { 23 lines.push(current); 24 } 25 current = ''; 26 } 27 else { 28 current += char; 29 } 30 } 31 32 if (current.trim() !== '') { 33 lines.push(current); 34 } 35 36 return lines; 37} 38 39function trimAndCleanArray(arr) { 40 return arr 41 .map(val => val.trim()) // Remove blank space 42 .filter(Boolean); // Remove empty values 43} 44 45function parseCSVLine(line, separator = ';') { // Transforme une ligne CSV brut en tableau 46 const results = []; 47 let current = ''; 48 let inQuotes = false; 49 50 for (let i = 0; i < line.length; i++) { 51 const char = line[i]; 52 const nextChar = line[i + 1]; 53 54 if (char === '"') { 55 if (inQuotes && nextChar === '"') { 56 current += '"'; // guillemet échappé 57 i++; 58 } else { 59 inQuotes = !inQuotes; 60 } 61 } 62 else if (char === separator && !inQuotes) { 63 results.push(current); 64 current = ''; 65 } 66 else { 67 current += char; 68 } 69 } 70 71 results.push(current); 72 return results; 73} 74 75function decodeCSVContent(content, separator = ';', hasHeader = true) { // Transforme un CSV brut en objet CSV 76 let rawLines = trimAndCleanArray(splitByObject(content)); // Sépare et nettoie les lignes 77 const lines = rawLines.map(line => parseCSVLine(line, separator)); // Sépare les lignes en colonnes 78 79 let header; 80 if(hasHeader) { // Si la première ligne est un header 81 header = lines.shift(); // Deplace la première ligne dans le header 82 } 83 else { 84 header = Array.from({length: lines[0].length}, (_, index) => 'Colonne ' + (index + 1)) // Sinon, genère un header (Colonne 1, Colonne 2...) 85 } 86 87 return { header, lines } 88} 89 90async function getFileInputContent(input) { // Récupère le contenu brut d'un input (à utiliser avec <input type="file" accept=".csv" />) 91 return await input.files[0].text(); 92} 93 94async function decodeInputCsvContent(input, separator = ';', hasHeader = true) { // Retourne le header et le contenu du fichier CSV dans un tableau 95 let csvContent = await getFileInputContent(input); 96 let { header, lines } = decodeCSVContent(csvContent, separator, hasHeader); 97 98 return { header, lines }; 99} 100 101function csvToObjects(mapping, lines, header) { 102 let columnIndexes = {}; 103 104 if(header) { 105 for (let key in mapping) { 106 columnIndexes[key] = header.indexOf(mapping[key]); 107 } 108 } 109 else { 110 columnIndexes = mapping; 111 } 112 113 const objects = []; 114 lines.forEach((line) => { 115 const lineObj = {}; 116 for (let key in columnIndexes) { 117 lineObj[key] = line[columnIndexes[key]]; 118 } 119 120 objects.push(lineObj); 121 }); 122 123 return objects; 124}
L'utilisation se fait de la manière suivante :
(js)1const csvContent = `Title;Date;Content;Le nom de l'auteur 2Mon super titre;2025-06-19;"Mon contenu ; avec des guillemets";Valentin 3Mon grand titre;2025-08-07;Mon projet;Benjamin`; 4 5// On peut utiliser decodeCSVContent ou decodeInputCsvContent (pour un input). 6// Le premier paramètre est le contenu brut ou l'input 7// Le deuxième est le séparateur (; par défaut) 8// Le troisième est s'il y a ou non un header (true par défaut) 9 10const { header, lines } = decodeCSVContent(csvContent); 11// header = [ "Title", "Date", "Content", "Le nom de l'auteur" ] 12// lines = [ 13// [ "Mon super titre", "2025-06-19", "Mon contenu ; avec des guillemets", "Valentin" ], 14// [ "Mon grand titre", "2025-08-07", "Mon projet", "Benjamin" ] 15// ] 16 17// Pour simplifier la manipulation des lignes, il est possible d'utiliser le fonction csvToObjects 18const mapping = { 19 'projectDate': 'Date', 20 'author': 'Le nom de l\'auteur' 21}; 22const objects = csvToObjects(mapping, lines, header); 23// objects = [ 24// { projectDate: "2025-06-19", author: "Valentin" }, 25// { projectDate: "2025-08-07", author: "Benjamin" } 26// ]
― Valentin LORTET