Simon CHABROL

Écriture et recherche indépendante (FR/EN)

Technicien de support IT

Dans ce nouvel et très court article, nous allons apprendre à manipuler des fichiers CSV en Javascript sans faire appel à des librairies, et plus particulièrement à convertir des fichiers CSV en JSON. Savoir manipuler de tels fichiers est très utile dans la mesure où il s’agit d’un format assez courant pour stocker et diffuser des données, en particulier dans le domaine de l’analytique et du machine learning. Un des inconvénients avec le Javascript est qu’il n’est pas possible de manipuler des fichiers CSV aussi facilement que des fichiers JSON, dans la mesure où la gestion de ce format n’est pas native. Il est donc important de comprendre comment fonctionne ce format, et de savoir comment il est possible de le manipuler en Javascript. Nous verrons donc brièvement comment fonctionne le format CSV, puis nous passerons à la partie pratique en apprenant à convertir un fichier CSV en JSON en Javascript.

Table des matières :

  1. Définition et comparaison avec d’autres formats
  2. Convertir des fichiers CSV en JSON
  3. Convertir un JSON en CSV
  4. Conclusions

Définition et comparaison avec d’autres formats

Le format CSV (pour “Comma Separated Value”, que l’on peut traduire en français par “Valeurs séparées par des virgules”) est un format de stockage de données qui prend la forme d’un fichier où l’on retrouve : Un première ligne avec les noms des colonnes Des lignes dont des informations correspondant aux intitulés des colonnes Voici un exemple d’un fichier très simpliste en CSV :

id,name,adress
1,simon,paris
2,marcel,nancy

On retrouve donc un première ligne avec l’ensemble des colonnes. Chaque colonne est séparée par une virgule. Puis nous trouvons les lignes contenues dans chacune des colonnes. Les informations sont également compartimentées à l’aide de virgules. En comparaison avec un autre format de stockage de données comme le JSON, le CSV présente certains avantages en termes d’ergonomie ce qui peut être très pratique notamment pour des transferts de base de données. Vous noterez également que le schéma des données est immédiatement défini à l’aide de la première ligne. Pour faire la comparaison avec un autre format de données lui aussi fréquent, voici la traduction en JSON des informations précédentes :

[
{
"id":1,
"name":"simon",
"adress":"paris"
},
{
"id":2,
"name":"marcel",
"adress":"nancy"
}
]

Comme vous pouvez le voir, le format JSON est plus verbeux que le format CSV. Il comporte notamment plus de caractères spéciaux comme des crochets. Pour le reste, les performances entre ces deux formats seront relativement similaires. Il peut y avoir un petit avantage pour le CSV dans la mesure où il contient moins de caractères, mais cela reste relativement négligeable. Le principal inconvénient du CSV est qu’il ne peut pas servir à représenter des données hiérarchisées ou relationnelles. Par conséquent, les cas d’usage sont donc un peu différents. On choisit souvent d’utiliser le JSON pour des échanges que l’on peut qualifier d’immédiats ou “à chaud”, comme par exemple l’envoi et la réception de données auprès d’une API. Le JSON est donc un peu plus rare lorsqu’il s’agit de manipuler des données en très grand nombre pour les exporter ou les importer dans un système.

Toutefois, dans la mesure où il est supporté nativement en Javascript, il peut être beaucoup plus intéressant de l’utiliser même si les informations sont volumineuses. Le CSV est quant à lui utilisé pour l’analytique et le machine learning, ainsi que pour l’exportation et l’importation de données. On aura donc tendance à le retrouver lors de transferts d’informations en grande quantité. C’est un format couramment utilisé lorsque l’on souhaite faire des importations/exportations de données en masse que vous avez du rencontrer dans de nombreux logiciels. Maintenant que nous avons vu comment fonctionne le CSV, et comment il se différencie du JSON, nous allons pouvoir passer à la pratique en codant un outil capable de convertir un fichier CSV en fichier JSON.

Convertir des fichiers CSV en JSON

Pour construire notre outil de conversion, nous allons avoir besoin dans un premier temps de créer un fichier CSV. Pour rappel, l’ensemble des codes disponibles sur ce site sont écrits en Javascript et exécutés dans l’environnement NodeJS. Vous pouvez donc tout d’abord ajouter le contenu suivant dans un fichier nommé “dataset.csv” :

id,prenom,ville
1,simon,paris
2,thomas,nancy
3,jeniffer,rome
4,caroline,londres

Une fois que cela est fait, il est possible de démarrer l’écriture de notre programme. Nous aurons uniquement besoin du module “fs”, une librairie native de NodeJS pour manipuler des fichiers. Commençons par le déclarer :

const fs = require('fs')

Nous allons à la suite déclarer une variable “Document” qui va contenir qui va contenir notre fichier CSV converti sous la forme d’un tableau. Il faudra parfois faire attention à choisir le bon caractère qui désigne un retour à la ligne. Ajoutons la ligne suivante :

var Document = fs.readFileSync('dataset.csv').toString().split('\r\n')

On peut à la suite déclarer une variable “Columns” qui va contenir le premier élément de ce tableau, soit la ligne avec les intitulés des colonnes :

var Columns = Document[0]

On peut avoir besoin pour cette étape de supprimer des caractères spéciaux comme des apostrophes par exemple. Une fois que cela est fait, nous pouvons supprimer cet élément de la variable “Document” :

Document.shift()

On peut ensuite transformer la variable “Columns” en un tableau à l’aide de l’instruction “split” avec le code suivant :

Columns = Columns.split(',')

On ajoute ensuite une boucle qui va récupérer un élément dans la variable “Document” et le découper en tenant compte de présence d’une virgule. Nous commençons donc d’abord par créer une boucle qui va itérer à travers la variable “Document”. On déclare ensuite une variable “Data” qui va contenir les éléments à pousser dans le JSON, puis une variable “Element” qui va contenir une ligne contenue dans la variable “Document” en la convertissant en un tableau (là aussi, nous convertissant cette ligne en un tableau en prenant en compte la virgule comme délimiteur des informations). Puis à l’aide d’une deuxième boucle, on peut ensuite stocker ces informations dans une variable “Data” avec le nom de la variable et sa valeur correspondante. Ces informations sont ensuite poussées dans une variable “Json” :

var Json = []

for (var i = 0; i < Document.length; i++) {
var Data = {}
var Element = Document[i].split(',')
for (var j = 0; j < Element.length; j++) {
Data[Columns[j]] = Element[j]
}
Json.push(Data)
}

Puis on sauvegarde le contenu dans un fichier JSON :

Data = JSON.stringify(Json)

fs.writeFileSync('data.json', Data, function (err) {
if (err) throw err
})

Et voici le contenu du fichier :

[
{
"id":"1",
"prenom":"simon",
"ville":"paris"
},
{
"id":"2",
"prenom":"thomas",
"ville":"nancy"
},
{
"id":"3",
"prenom":"jeniffer",
"ville":"rome"},
{
"id":"4",
"prenom":"caroline",
"ville":"londres"
}
]

Le cas est ici assez simple. Cela peut devenir un peu compliqué avec un fichier où certaines colonnes sont amenées à contenir plusieurs informations. Dans ce cas, la délimitation est souvent remplacée par un point virgule pour les colonnes, et par des virgules pour les sous-ensembles. Exemple avec ce nouveau fichier :

id;prenom;ville
1;simon,paul;paris
2;thomas;nancy,marseille
3;jeniffer,laurence;rome
4;caroline;londres,dunkerque

Bien entendu, on peut également avoir le cas où les colonnes sont séparées par des virgules, et les sous-ensembles séparés par des points virgules. On peut d’ailleurs rencontrer plusieurs façons d’ajouter plusieurs valeurs dans une même colonne. En voici quelques exemples :

simon,paul
simon paul
"simon,paul"

On veut donc savoir quel est le séparateur utilisé pour les colonnes, car cela nous aidera notamment à savoir comment séparer les sous-ensembles contenus dans les colonnes. Commençons donc d’abord par définir une variable “SeparatorColumn” et une variable “SeparatorValues” (il faut ajouter ces variables juste en dessous de la ligne “ var Columns = Document[0] “) :

var SeparatorColumn
var SeparatorValues

Puis nous mettons en place des conditions pour définir ces valeurs. Si le séparateur pour les colonnes est la virgule, nous utilisons le point virgule pour séparer les sous-ensembles. Dans le cas contraire, nous utiliserons alors le point virgule comme séparateur des colonnes, et la virgule pour séparer les sous-ensembles. Pour une utilisation en conditions réelles, il faudrait signaler à l’utilisateur une incohérence si cette ligne contient à la fois des virgules et des points virgules) :

 if (Columns.includes(',') === true) {
SeparatorColumn = ','
SeparatorValues = ';'
} else if (Columns.includes(';') === true) {
SeparatorColumn = ';'
SeparatorValues = ','
}

Bien entendu, on peut faire évoluer ce code si d’autres séparateurs sont utilisés, en particulier pour les sous-ensembles. On va ensuite modifier la programme en changeant dans un premier temps la façon dont les entêtes des colonnes sont récupérées :

Columns = Columns.split(SeparatorColumn)

On met également à jour la boucle d’extraction des informations :

for (var i = 0; i < Document.length; i++) {
var Data = {}
var Element = Document[i].split(SeparatorColumn)
for (var j = 0; j < Element.length; j++) {
var Length = (Element[j].split(SeparatorValues)).length
if (Length > 1) {
Data[Columns[j]] = Element[j].split(SeparatorValues)
} else {
Data[Columns[j]] = Element[j]
}
}
Json.push(Data)
}

Dans le cas où la séparation des valeurs d’une colonne consiste à mettre les valeurs entre guillemets et à les séparer par des virgules, il faudra un peut adapter le travail de la variable “Element” en utilisant une expression régulière :

var Element = Document[i].toString().replace(/\"/g,'').split(SeparatorColumn)

Et voici le contenu du fichier :

[
{
"id":"1",
"prenom":["simon","paul"],
"ville":"paris"
},
{
"id":"2",
"prenom":"thomas",
"ville":["nancy","marseille"]},
{
"id":"3",
"prenom":["jeniffer","laurence"],
"ville":"rome"
},
{
"id":"4",
"prenom":"caroline",
"ville":["londres","dunkerque"]
}
]

Dernier problème à corriger, la conservation des nombres dans leur format d’origine. En effet, dans le format JSON, les valeurs numériques sont conservées en tant que telles. Elles ne sont donc pas considérées comme du texte. Il faut tester les valeurs pour savoir s’il s’agit d’un nombre ou d’autre chose. Et s’il s’agit d’un nombre, il faut alors pousser la valeur mais avec le bon format. Il faut donc procéder à quelques changements dans la boucle de récupération des informations :

for (var i = 0; i < Document.length; i++) {
var Data = {}
var Element = Document[i].split(SeparatorColumn)
for (var j = 0; j < Element.length; j++) {
var Length = (Element[j].split(SeparatorValues)).length
if (Length > 1) {
var Values = Element[j].split(SeparatorValues)
for (var k = 0; k < Values.length; k++) {
if (isNaN(Values[k]) === false) {
Values[k] = parseInt(Values[k])
}
}
Element[j] = Values
Data[Columns[j]] = Element[j]
} else {
if (isNaN(Element[j]) === false) {
Data[Columns[j]] = parseInt(Element[j])
} else {
Data[Columns[j]] = Element[j]
}
}
}
Json.push(Data)
}

Et voici le fichier que l’on obtient :

[
{
"id":1,
"prenom":["simon","paul"],
"ville":"paris"
},
{
"id":2,
"prenom":"thomas",
"ville":["nancy","marseille"]
},
{
"id":3,
"prenom":["jeniffer","laurence"],
"ville":"rome"
},
{
"id":4,
"prenom":"caroline",
"ville":["londres","dunkerque"]
}
]

Enfin, on peut faire face au cas de figures où des lignes comportent des informations entre guillemets. Exemple :

1,"Hello, World",Simon
2,"Bye, World",Thomas

Les éléments entre guillemets représentent une seule colonne malgré la présence d’une virgule. Il faut donc ici veiller à mettre en place une logique pour analyser chacune des lignes et modifier par exemple le séparateur de façon à ne pas faire d’erreur dans la découpe des lignes. On peut procéder avec cet exemple de code :

var Data = [
['1,"Hello, World",Simon'],
['2,"Bye, World",Thomas']
]


for (var j = 0; j < Data.length; j++) {
var Arr = […Data[j].toString()]
var Quote = 0

for (var i = 0; i < Arr.length; i++) {
if (Arr[i] == '"' && Quote === 0) {
Quote += 1
} else if (Arr[i] == '"' && Quote === 1) {
Quote = 0
}

if (Arr[i] == ',' && Quote === 0) {
Arr[i] = ';'
}
}
var Result = (Arr.join('')).split(';')
for (var k = 0; k < Result.length; k++) {
if (isNaN(parseInt(Result[k]) === false) {
Result[k] = parseInt(Result[k])
}
}
console.log(Result)
}

// [1,'Hello, World','Simon'],
// [2,'Bye, World','Thomas']

La logique est assez primitive mais cela fonctionne. Comme vous pouvez le constater, manipuler des fichiers CSV n’est pas si compliqué lorsque l’on comprend ce format.

Convertir un JSON en CSV

On peut également apprendre à mettre en œuvre l’opération inverse qui consiste à convertir un fichier JSON au format CSV. Les opérations suivantes seront réalisées avec le précédent fichier JSON. Vous trouverez le code complet de l’implémentation de cette méthode en suivant ce lien . On va donc d’abord ouvrir le document JSON en question puis récupérer la liste des colonnes dans le premier sous-ensemble pour construire notre référentiel de colonnes :

var Document = JSON.parse(fs.readFileSync('dataset.json').toString())

var Columns = []

for (var keys in Document[0]) {
Columns.push(keys)
}

Ensuite, on va recomposer un grand tableau avec l’ensemble des valeurs à insérer pour chacune des colonnes. Pour éviter le problème de valeurs qui ne sont pas dans le même ordre dans chacun des sous-objets du JSON, on va rechercher les valeurs correspondantes en utilisant le nom des colonnes et non pas l’index de ces dernières :

var Values = []

for (var i = 0; i < Document.length; i++) {
var List = []
for (var j = 0; j < Columns.length; j++) {
List.push(Document[i][Columns[j]])
}
Values.push(List)
}

Ne reste plus qu’à joindre les différents tableaux ainsi générés et à écrire un nouveau fichier CSV que l’on va nommer “datasetFromJSON.csv” :

fs.writeFileSync('datasetFromJSON.csv', Columns.join(';')+'\n', function (err) {
if (err) throw err
})

for (var i = 0; i < Document.length; i++) {
fs.appendFileSync('datasetFromJSON.csv', Values[i].join(';')+'\n', function (err) {
if (err) throw err
})
}

Exemple de résultat :

id;prenom;ville
1;simon,paul;paris
2;thomas;nancy,marseille
3;jeniffer,laurence;rome
4;caroline;londres,dunkerque

Conclusions

Nous avons donc vu dans cet article ce qu’est le format CSV, comment il fonctionne, ainsi que ses avantages et inconvénients par rapport au JSON. Nous avons également appris à mettre en place une méthode permettant de convertir un fichier CSV en JSON sans appel à une librairie externe. Savoir manipuler le CSV vous sera très utile lorsque vous serez amené à manipuler des données dans ce format ou lorsqu’il faudra implémenter une solution nécessitant de lire des fichiers dans ce format.

Laisser un commentaire