IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Java Discussion :

regex CSV avec des guillemets


Sujet :

Java

  1. #21
    Expert confirmé
    Avatar de Loceka
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    2 276
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 2 276
    Points : 4 847
    Points
    4 847
    Par défaut
    C'est possible avec une regex mais c'est peut-être pas le plus lisible.

    Quoi qu'il en soit c'est à la limite de ce qu'on peut faire avec les expressions régulières :
    Code X : Sélectionner tout - Visualiser dans une fenêtre à part
    /((?:"(?:\\"|[^"])*"\s*)|(?:[^,"]*\s*)),?/g

    J'ai testé et ça match bien chaque partie de cette chaîne-là :
    Code X : Sélectionner tout - Visualiser dans une fenêtre à part
    "Maman",Papa,"Julie, \"Franck\"\net Tom","Mamy","Papy"

    Bien entendu vu que le Java c'est super verbeux c'est tout de suite moins joli :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    String s = "\"Maman\",Papa,\"Julie, \\\"Franck\\\"\net Tom\",\"Mamy\",\"Papy\"";
    String regex = "((?:\"(?:\\\\\"|[^\"])*\"\\s*)|(?:[^,\"]*\\s*)),?";
    Pattern p = Pattern.compile(regex);
    Matcher m = p.matcher(s);
    System.out.println("Chaîne : "+ s +"\nRegex : "+ regex);
    int hit = 0;
    while(m.find()) {
    	System.out.println(++hit + " : " + m.group(1));
    }
    Par contre ça match aussi la chaîne vide, donc y'a une occurrence de trop à la fin, j'arrive pas à l'enlever.

  2. #22
    Rédacteur
    Avatar de thierryler
    Homme Profil pro
    Inscrit en
    Octobre 2007
    Messages
    4 078
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 078
    Points : 12 815
    Points
    12 815
    Par défaut
    @william44290 : Je pense que ça ne marche pas. Je cherche un peu les coups, mais si mon fichier csv contient la ligne suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    "1","Médor","Rouge,"Jaune bizare",Noir",32
    Cela dit, l'idée est intéressante. Je vais surement la mettre en annexes de mon tuto.


    @Loceka :
    Faut pas oublier que les CSV peuvent avoir des champs vides en plein centre aussi

  3. #23
    Membre confirmé
    Avatar de william44290
    Homme Profil pro
    Responsable de service informatique
    Inscrit en
    Juin 2009
    Messages
    400
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France

    Informations professionnelles :
    Activité : Responsable de service informatique

    Informations forums :
    Inscription : Juin 2009
    Messages : 400
    Points : 575
    Points
    575
    Par défaut
    pour la valeur vide
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    String line1b = "\"Maman\",\"Papa\",\"Julie, Franck et Tom\",,\"Papy\"";
    il me semble que ce n'est pas correct, si la valeur était vide tu aurais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    String line1b = "\"Maman\",\"Papa\",\"Julie, Franck et Tom\","\"\"",\"Papy\"";
    et l'algo fonctionne.

  4. #24
    Membre confirmé
    Avatar de william44290
    Homme Profil pro
    Responsable de service informatique
    Inscrit en
    Juin 2009
    Messages
    400
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France

    Informations professionnelles :
    Activité : Responsable de service informatique

    Informations forums :
    Inscription : Juin 2009
    Messages : 400
    Points : 575
    Points
    575
    Par défaut
    je pense aussi que ce cas n'est pas possible :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    "1","Médor","Rouge,"Jaune bizare",Noir",32
    Il me semble que l'export cvs ferait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    "1","Médor","Rouge,"Jaune bizare",Noir","32"

  5. #25
    Rédacteur
    Avatar de thierryler
    Homme Profil pro
    Inscrit en
    Octobre 2007
    Messages
    4 078
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 078
    Points : 12 815
    Points
    12 815
    Par défaut
    Ok pour 1b comme ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    String regexLine1 = "\",\"";
    String[] slipLine1;
    String line1b = "\"Maman\",\"Papa\",\"Julie, Franck et Tom\",\"\",\"Papy\"";
    Du coup je ne comprend pas comment ça marche...

  6. #26
    Rédacteur
    Avatar de thierryler
    Homme Profil pro
    Inscrit en
    Octobre 2007
    Messages
    4 078
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 078
    Points : 12 815
    Points
    12 815
    Par défaut
    En fait c'est le champ "Rouge,"Jaune bizare",Noir" qui pose problème

  7. #27
    Expert confirmé
    Avatar de Loceka
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    2 276
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 2 276
    Points : 4 847
    Points
    4 847
    Par défaut
    Citation Envoyé par thierryler Voir le message
    @Loceka :
    Faut pas oublier que les CSV peuvent avoir des champs vides en plein centre aussi
    Oui, c'est justement pour ça que j'ai fait en sorte que ça match la chaîne vide... Mais l'inconvéniant c'est que ça matchera toujours une occurrence en trop (donc c'est simple à prendre en compte mais c'est moche).

    Preuve que ça marche pour champs vides :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    String s = "\"Maman\",Papa,\"\",,\"Julie, \\\"Franck\\\"\net Tom\",\"Mamy\",\"Papy\"";
    String regex = "((?:\"(?:\\\\\"|[^\"])*\"\\s*)|(?:[^,\"]*\\s*)),?";
    Pattern p = Pattern.compile(regex);
    Matcher m = p.matcher(s);
    System.out.println("Chaîne : "+ s +"\nRegex : "+ regex);
    int hit = 0;
    while(m.find()) {
    	System.out.println(++hit + " : " + m.group(1));
    }
    Résultat :
    Code X : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Chaîne : "Maman",Papa,"",,"Julie, \"Franck\"
    et Tom","Mamy","Papy"
    Regex : ((?:"(?:\\"|[^"])*"\s*)|(?:[^,"]*\s*)),?
    1 : "Maman"
    2 : Papa
    3 : ""
    4 : 
    5 : "Julie, \"Franck\"
    et Tom"
    6 : "Mamy"
    7 : "Papy"
    8 :
    Si je n'avais pas écrit la regex pour qu'elle prenne en compte les champs vides, ç'aurait été plus simple à écrire...

    Edit :
    Citation Envoyé par thierryler Voir le message
    En fait c'est le champ "Rouge,"Jaune bizare",Noir" qui pose problème
    Forcément, ce n'est pas un champs CSV bien formé. Aucun parseur CSV ne devrait l'interpréter correctement à mon avis. Il faut doubler les guillemets lorsqu'ils sont inclus dans la chaîne :
    Les champs texte peuvent également être délimités par des guillemets (1). Lorsqu'un champ contient lui-même des guillemets (2), ils sont doublés afin de ne pas être considérés comme début ou fin du champ. Si un champ contient le séparateur (3) (virgule, points-virgules, etc.), il est obligatoire d'ajouter des guillemets afin que le séparateur soit échappé.
    (bon, dans ce cas ma regex n'est plus tout à fait correcte vu que je pensais qu'il étaient échappés par un anti-slash, mais elle est facile à corriger :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    String regex = "((?:\"(?:\"\"|[^\"])*\"\\s*)|(?:[^,\"]*\\s*)),?";
    )

  8. #28
    Rédacteur
    Avatar de thierryler
    Homme Profil pro
    Inscrit en
    Octobre 2007
    Messages
    4 078
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 078
    Points : 12 815
    Points
    12 815
    Par défaut
    Ca devient chaud là...

    Par contre je pense que ça ne devrait pas prendre le retour à la ligne en compte. Je m'explique. Pour l'instant, je lis ligne par ligne le fichier, considérant que chaque ligne est autonome. Comment je fais pour savoir si je suis dans une ligne ou au milieu d'une ligne sinon...

    Là ça dépasse le cadre de mes compétences.

  9. #29
    Membre confirmé
    Avatar de william44290
    Homme Profil pro
    Responsable de service informatique
    Inscrit en
    Juin 2009
    Messages
    400
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France

    Informations professionnelles :
    Activité : Responsable de service informatique

    Informations forums :
    Inscription : Juin 2009
    Messages : 400
    Points : 575
    Points
    575
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    "1","Médor","Rouge,"Jaune bizare",Noir","32"
    en fait il y a erreur le cvs aurait sorti cela :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    "1","Médor","Rouge,"Jaune bizare","Noir","32"

  10. #30
    Rédacteur
    Avatar de thierryler
    Homme Profil pro
    Inscrit en
    Octobre 2007
    Messages
    4 078
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 078
    Points : 12 815
    Points
    12 815
    Par défaut
    En fait plutôt ça si on prend en compte la citation de Loceka, en doublant les guillemets :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    "1","Médor","Rouge,""Jaune bizare"",Noir","32"

  11. #31
    Membre confirmé
    Avatar de william44290
    Homme Profil pro
    Responsable de service informatique
    Inscrit en
    Juin 2009
    Messages
    400
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France

    Informations professionnelles :
    Activité : Responsable de service informatique

    Informations forums :
    Inscription : Juin 2009
    Messages : 400
    Points : 575
    Points
    575
    Par défaut
    Citation Envoyé par thierryler Voir le message
    Ca devient chaud là...

    Par contre je pense que ça ne devrait pas prendre le retour à la ligne en compte. Je m'explique. Pour l'instant, je lis ligne par ligne le fichier, considérant que chaque ligne est autonome. Comment je fais pour savoir si je suis dans une ligne ou au milieu d'une ligne sinon...

    Là ça dépasse le cadre de mes compétences.
    Perso j'utilise :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
                Scanner scanner= new Scanner(fImport);
                while (scanner.hasNextLine()) {
                    String line = scanner.nextLine();
                    etc ...
    Chaque line est bien un enregistrement.

  12. #32
    Rédacteur
    Avatar de thierryler
    Homme Profil pro
    Inscrit en
    Octobre 2007
    Messages
    4 078
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 078
    Points : 12 815
    Points
    12 815
    Par défaut
    Heu, si on revient à mon chiens.csv, dans lequel j'ajoute des retours à la ligne dans médor, ça s'utilise comment ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
     
    # Fichier avec la liste des chiens du magasin
    # Propriété de Thierry
     
    # Titres id; Prénom; Couleur et Age.
    "Id";"Prénom";"Couleur";"Age"
     
    "1";"Titi";"Jaune";"5"
    "2";"Médor de 
    la branche de mes
    deux parents";"Noir";"10"
    "3";"Pitié";"Noir";"5"
    "4";"Juju";"Gris";"5"
    "5";"Vanille";"Blanc";"7"
    "6";"Chocolat";"Marron";"12"
    "7";"Milou";"Blanc";"3"
     
    # La ligne suivante (Idefix) a trois couleur avec un point-virgule dedans
    "8";"Idefix";"Blanc; noir et beige";"14"
     
    "9";"Pluto";"Jaune";"17"
    10;Dingo;Roux;1

  13. #33
    Expert confirmé
    Avatar de Loceka
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    2 276
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 2 276
    Points : 4 847
    Points
    4 847
    Par défaut
    Citation Envoyé par thierryler Voir le message
    Ca devient chaud là...

    Par contre je pense que ça ne devrait pas prendre le retour à la ligne en compte. Je m'explique. Pour l'instant, je lis ligne par ligne le fichier, considérant que chaque ligne est autonome. Comment je fais pour savoir si je suis dans une ligne ou au milieu d'une ligne sinon...

    Là ça dépasse le cadre de mes compétences.
    Et pourtant...
    J'ai déjà eu affaire à des CSV dont les champs étaient sur plusieurs lignes.
    Auquel cas les champs doivent être entouré par des guillemets. Les champs sans guillemets, eux, ne doivent contenir ni saut de ligne ni séparateur.

    Une ligne CSV se termine si et seulement si un saut de ligne survient après un champ. Un champ peut être vide, une chaîne sans saut de ligne ni séparateur ou une chaîne délimitée par des guillemets.

    En effet la regex que j'ai écrite ne prend pas ça en compte mais c'est pas bien complexe à réparer.

  14. #34
    Membre confirmé
    Avatar de william44290
    Homme Profil pro
    Responsable de service informatique
    Inscrit en
    Juin 2009
    Messages
    400
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France

    Informations professionnelles :
    Activité : Responsable de service informatique

    Informations forums :
    Inscription : Juin 2009
    Messages : 400
    Points : 575
    Points
    575
    Par défaut
    En fait les lignes 11 et 12 n'existe pas. Elle n'en forment qu'une seule en CSV.

  15. #35
    Rédacteur
    Avatar de thierryler
    Homme Profil pro
    Inscrit en
    Octobre 2007
    Messages
    4 078
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 078
    Points : 12 815
    Points
    12 815
    Par défaut
    @william44290 : ça devrait être comment en CSV ?


    Au début de mon tuto, je dis que c'est un sujet qui a l'air simple mais qui est en réalité super complexe... J'avais pas tord

  16. #36
    Membre confirmé
    Avatar de william44290
    Homme Profil pro
    Responsable de service informatique
    Inscrit en
    Juin 2009
    Messages
    400
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France

    Informations professionnelles :
    Activité : Responsable de service informatique

    Informations forums :
    Inscription : Juin 2009
    Messages : 400
    Points : 575
    Points
    575
    Par défaut
    le fichier CSV serait :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    "Id";"Prénom";"Couleur";"Age"
    "1";"Titi";"Jaune";"5"
    "2";"Médor de la branche de mes deux parents";"Noir";"10"
    "3";"Pitié";"Noir";"5"
    "4";"Juju";"Gris";"5"
    "5";"Vanille";"Blanc";"7"
    "6";"Chocolat";"Marron";"12"
    "7";"Milou";"Blanc";"3"
    "8";"Idefix";"Blanc; noir et beige";"14"
    "9";"Pluto";"Jaune";"17"
    "10";"Dingo";"Roux";"1"

  17. #37
    Membre confirmé
    Avatar de william44290
    Homme Profil pro
    Responsable de service informatique
    Inscrit en
    Juin 2009
    Messages
    400
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France

    Informations professionnelles :
    Activité : Responsable de service informatique

    Informations forums :
    Inscription : Juin 2009
    Messages : 400
    Points : 575
    Points
    575
    Par défaut
    alors un essai avec excel :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Id;Prénom;Couleur;Age
    1;Titi;"Jaune ""couleur bizarre""";5
    2;Médor de la branche de mes deux parents;Noir;10
    3;Pitié;Noir;5
    4;Juju;Gris;5
    5;Vanille;Blanc;7
    6;Chocolat;Marron;12
    7;Milou;Blanc;3
    8;Idefix;"Blanc; noir et beige";14
    9;Pluto;Jaune;17
    10;Dingo;Roux;1
    Mon algo ne fonctionne plus

  18. #38
    Expert confirmé
    Avatar de Loceka
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    2 276
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 2 276
    Points : 4 847
    Points
    4 847
    Par défaut
    le mien si
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    String s = "# Fichier avec la liste des chiens du magasin\n# Propriété de Thierry\n \n# Titres id; Prénom; Couleur et Age.\n\"Id\";\"Prénom\";\"Couleur\";\"Age\"\n \n\"1\";\"Titi\";\"Jaune\";\"5\"\n\"2\";\"Médor de \nla branche de mes\ndeux parents\";\"Noir\";\"10\"\n\"3\";\"Pitié\";\"Noir\";\"5\"\n\"4\";\"Juju\";\"Gris\";\"5\"\n\"5\";\"Vanille\";\"Blanc\";\"7\"\n\"6\";\"Chocolat\";\"Marron\";\"12\"\n\"7\";\"Milou\";\"Blanc\";\"3\"\n \n# La ligne suivante (Idefix) a trois couleur avec un point-virgule dedans\n\"8\";\"Idefix\";\"Blanc; noir et beige\";\"14\"\n \n\"9\";\"Pluto\";\"Jaune\";\"17\"\n10;Dingo;Roux;1";
    s += "\n";
    String delim = ";";
    String space = "[ \\t\\x0B\\f]";
    String nl = "(?:\\r\\n|\\n\\r|\\n)";
    String regex = space + "*(?:"+nl+"|#.*"+nl+")|(?:((?:\"(?:\"\"|[^\"])*\")|(?:[^"+delim+"\""+nl+"]*))"+space+"*("+delim+"|"+nl+"))";
    Pattern p = Pattern.compile(regex);
    Matcher m = p.matcher(s);
    System.out.println("Chaîne : "+ s +"\nRegex : "+ regex);
    int line = 1;
    int col = 1;
    while(m.find()) {
    	if (m.start(1) != -1) {
    		System.out.println(line+","+col++ + " : " + m.group(1) + " [" + m.group(2) +"]");
    		if (!m.group(2).equals(delim)) {
    			col = 1;
    			line++;
    		}
    	}
    }
    NB : il faut obligatoirement que le fichier se termine par un retour charriot (\n, \r\n ou \n\r) pour que ça marche...

  19. #39
    Rédacteur
    Avatar de thierryler
    Homme Profil pro
    Inscrit en
    Octobre 2007
    Messages
    4 078
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 078
    Points : 12 815
    Points
    12 815
    Par défaut
    @william44290 je ne comprend pas, si mon champ a un retout chariot, par exemple s'il correspond à des paragraphes d'un article, alors il faut bien conserver les \n...

    @loceka : rien ne me garanti que j'aurai bien un retour chariot à la fin, sauf si le programme l'ajoute lui meme

  20. #40
    Expert confirmé
    Avatar de Loceka
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    2 276
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 2 276
    Points : 4 847
    Points
    4 847
    Par défaut
    Ecoute, tu demandais une regex pour faire ça, je t'en écris une qui fait le café (suppression des commentaires et des lignes vides, prise en compte des champs vides, prise en compte des champs sur plusieurs lignes, ...) après si tu trouves que c'est la mer à boire d'ajouter un "\n" à la fin de ton buffer ou String, c'est toi que ça regarde.

    Pour moi le sujet est résolu.

    PS :
    Un merci aurait été appréciable.

Discussions similaires

  1. [XL-2010] Convertir plusieurs fichiers excel en csv avec des guillemets
    Par karido-74 dans le forum Macros et VBA Excel
    Réponses: 41
    Dernier message: 29/01/2014, 18h32
  2. [CSV] importation CSV avec des guillemets
    Par trash_board dans le forum Langage
    Réponses: 3
    Dernier message: 12/09/2006, 14h08
  3. Réponses: 9
    Dernier message: 28/10/2005, 11h43
  4. [C#] Prob IndexOf sous Pocket Pc avec des guillemets
    Par freddyboy dans le forum Windows Mobile
    Réponses: 7
    Dernier message: 10/06/2004, 09h57

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo