EN · DE · RU · FR · ES

#1876 : CSVParser.java

projectforge-common/src/main/java/org/projectforge/common/CSVParser.java Classe utilitaire — package org.projectforge.common, projectforge-common/src/main/java/org/projectforge/common/CSVParser.java 342 lignes · 248 code · 57 commentaires · 37 vides
Analyseur CSV (valeurs séparées par des virgules) personnalisé avec une architecture d'analyseur lexical/analyseur syntaxique écrite à la main. Lit à partir d'un java.io.Reader et tokenise les données CSV caractère par caractère, prenant en charge les champs entre guillemets, les sauts de ligne intégrés dans les cellules entre guillemets, les guillemets doubles échappés (convention ""), les séparateurs de champ configurables, le mappage des noms de colonnes d'en-tête et la détection BOM UTF-8. Écrit par Kai Reinhard et H. Spiewok (2005), il est antérieur et évite les dépendances externes de bibliothèque CSV.

Architecture

Importations

Architecture de l'analyseur — Analyseur lexical écrit à la main

Plutôt que d'utiliser des expressions régulières ou un générateur d'analyseur, CSVParser implémente un analyseur lexical caractère par caractère avec un tampon de réinjection. Cette conception privilégie le contrôle sur la gestion des erreurs et les performances pour le sous-ensemble spécifique de formatage CSV utilisé par ProjectForge.

Composants principaux

Énumération Type

enum Type { EOF, EOL, CHAR }

Types de jetons : Fin de fichier, Fin de ligne ou données de caractère. Cela pilote la machine à états de l'analyseur.

Gestion du flux de caractères

Gestion de la BOM UTF-8

skipBOM() est appelée lors de la construction pour détecter et ignorer un marqueur d'ordre d'octets UTF-8 (\uFEFF) au début du fichier. Si aucune BOM n'est présente, le premier caractère est réinjecté (unread). Cela permet une analyse correcte des fichiers CSV exportés depuis Microsoft Excel, qui inclut une BOM pour les fichiers UTF-8.

Analyse des cellules (parseCell)

La logique principale d'analyse CSV gère ces cas :

CasComportement
Cellule sans guillemetsLes caractères sont accumulés jusqu'au séparateur ou à la fin de ligne
Cellule entre guillemets ("...")Les caractères entre guillemets sont accumulés ; les guillemets doivent être correctement fermés
Guillemet échappé ("")Deux guillemets doubles consécutifs dans une cellule entre guillemets représentent un caractère de guillemet littéral
Saut de ligne intégréLes sauts de ligne dans les cellules entre guillemets sont conservés (valeurs de cellule multilignes)
Espace blanc finalLes espaces blancs après le guillemet fermant sont ignorés ; attend un séparateur ou une fin de ligne ensuite
Guillemet non ferméLève une RuntimeException avec un message d'erreur descriptif incluant le numéro de ligne/colonne

Analyse de ligne (parseLine)

Lit les cellules jusqu'à la fin de ligne ou la fin de fichier, en les collectant dans une List<String>. Renvoie null à la fin du fichier (pas une liste vide — les appelants peuvent distinguer la fin du fichier des lignes vides).

Support des colonnes d'en-tête (parseHeadCols / getCell)

Pour les fichiers CSV avec une ligne d'en-tête, parseHeadCols() lit la première ligne et construit une colMap : Map<String, Integer> mappant les noms de colonnes à leur index positionnel. Les appels ultérieurs à getCell(List<String>, nomcolonne) récupèrent les valeurs par nom de colonne plutôt que par position. Cela permet un accès aux colonnes nommées à la manière d'Excel.

Messages d'erreur

Trois constantes d'erreur distinctes fournissent des diagnostics spécifiques :

ERROR_UNEXPECTED_QUOTATIONMARK = "Guillemet inattendu \" (uniquement autorisé dans les cellules entre guillemets)."
ERROR_QUOTATIONMARK_MISSED_AT_END_OF_CELL = "Guillemet \" manquant à la fin de la cellule."
ERROR_DELIMITER_OR_NEW_LINE_EXPECTED_AFTER_QUOTATION_MARK = "Délimiteur ou nouvelle ligne attendu après le guillemet."
ERROR_UNEXPECTED_CHARACTER_AFTER_QUOTATION_MARK = "Caractère inattendu après le guillemet."

Chaque message est enrichi des numéros de ligne et de colonne via createMessage().

Intégration avec CSVWriter

CSVParser utilise CSVWriter.DEFAULT_CSV_SEPARATOR_CHAR (';' — point-virgule) comme séparateur par défaut. C'est la convention CSV européenne (Microsoft Excel dans les paramètres régionaux allemands utilise le CSV délimité par des points-virgules). Le séparateur est configurable via setCsvSeparatorChar().

Limitations de conception

Cette implémentation personnalisée a été écrite en 2005, bien avant qu'Apache Commons CSV (publié en 2014) ou OpenCSV ne soient largement disponibles. À l'époque, le JDK n'avait pas de support CSV intégré. Le code a été maintenu avec des améliorations progressives : gestion de la BOM (commit 2024), support des champs entre guillemets multilignes et corrections de fautes de frappe via codespell.

Historique Git

868d6abb7 2025 -> 2026
161d71602 WIP : CSVParser : caractères BOM.
dfb2378df WIP : CSVParser : multilignes etc.
63081666f En-têtes de fichiers source : 2024 -> 2025.
a73905c14 Correction de fautes de frappe dans les répertoires projectforge*/ Trouvé via codespell
a72903e36 *.java, *.kt : StringBuffer -> StringBuilder.
b6092df09 Copyright 2023 -> 2024
ab45d51fa Copyright 2001-2022 -> 2001-2023.