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

Langage Java Discussion :

regex remplacer toutes les virgules entre double quote


Sujet :

Langage Java

  1. #1
    Nouveau membre du Club
    Inscrit en
    Février 2006
    Messages
    49
    Détails du profil
    Informations personnelles :
    Âge : 38

    Informations forums :
    Inscription : Février 2006
    Messages : 49
    Points : 33
    Points
    33
    Par défaut regex remplacer toutes les virgules entre double quote
    Bonjour à tous,

    Je travaille sur un traitement Batch qui traite un fichier avec pour séparateur la virgule. Si une des zones contient déjà une virgule, elle se retrouve entre double quote.

    exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    data1,data2,data3,data4
    data1,"data2a,data2b,data2c",data3,"data4a,data4b"
    data1,"data2a,data2b","data3a,data3b",data4
    data1,data2,data3,data4
    et j'aimerai remplacer le séparateur virgule par un autre dès qu'il est entre double quote pour obtenir quelque chose du genre:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    data1,data2,data3,data4
    data1,data2a;data2b;data2c,data3,data4a;data4b
    data1,data2a;data2b,data3a;data3b,data4
    data1,data2,data3,data4
    j'ai cherché à utiliser les regex mais je galère un peu... mes données contiennent tous types de caractères ( "/.&-)

    j'ai essayé ça, mais ça ne fonctionne que lorsqu'il y a une seule virgule.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
        Pattern p = Pattern.compile("\"[\w .&-]*,[\w .&-]*\"");
        Matcher m = p.matcher(data);
        m.replaceAll("$1$2");
    il doit bien y avoir une solution pour supprimer toutes ces virgules entre double-quote, si vous avez une idée je suis preneur.

    Sinon, remplacer toutes les virgules qui ne sont pas entre double-quote afin d'utiliser un autre séparateur me va aussi...mais ce n'est peut être pas plus simple

    Merci d'avance pour votre aide

  2. #2
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Salut,

    Au lieu de le faire avec une seul expression, pourquoi ne pas faire :

    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
    public static void main(String[] args) {
       System.out.println(replaceComma("data1,\"data2a,data2b,data2c\",data3,\"data4a,data4b\""));
       System.out.println(replaceComma("data1,\"data2a,data2b\",\"data3a,data3b\",data4"));
    }
     
    public static String replaceComma(String s) {	
        final Matcher matcher = Pattern.compile("\".*?\"").matcher(s);
     
        final StringBuffer sb = new StringBuffer();
        while( matcher.find() ) {
            matcher.appendReplacement(sb, matcher.group().replaceAll("\"", "").replaceAll(",", ";"));
        }
     
        return sb.toString();
     
    }
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  3. #3
    Nouveau membre du Club
    Inscrit en
    Février 2006
    Messages
    49
    Détails du profil
    Informations personnelles :
    Âge : 38

    Informations forums :
    Inscription : Février 2006
    Messages : 49
    Points : 33
    Points
    33
    Par défaut
    Effectivement, si ce n'est pas possible avec une seul regex ça peut être une solution. Je teste ça demain.

  4. #4
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 842
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 842
    Points : 6 522
    Points
    6 522
    Par défaut
    Tu peux le faire en une pattern:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Pattern p = Pattern.compile("(?:\\G(?<=[^\"])|\"([^\",]*)),([^\",]*)\"?");
    String result = p.matcher(s).replaceAll("$1;$2");
    \G marque la position dans la chaîne juste après l'occurrence précédente, ce qui fait qu'une fois que la branche "([^",]*) a réussi toutes les autres occurrences seront contiguës jusqu'au " fermant. Une fois ce dernier atteint, la condition (?<=[^"]) rompt cette contiguïté.

    Cette pattern ne gère pas tous les cas de figure. Par exemple, pour figurer un " littéral il faut l'échapper (normalement avec un autre, comme ça "", mais on peut aussi trouver un antislash). Si tu veux que la pattern gère ce cas, il faudra l'adapter.

    Maintenant il existe une foultitude de librairies pour le csv en java. Peut-être que la modification que tu cherches à faire n'est pas du tout nécessaire.
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  5. #5
    Nouveau membre du Club
    Inscrit en
    Février 2006
    Messages
    49
    Détails du profil
    Informations personnelles :
    Âge : 38

    Informations forums :
    Inscription : Février 2006
    Messages : 49
    Points : 33
    Points
    33
    Par défaut
    je n'ai pas précisé une chose, je ne suis pas sur du Java a proprement parlé... j'utilise Tibco BusinessWorks.
    je peux ajouter du code Java mais ce n'est pas forcement "le plus simple" c'est pour cette raison que je n'ai pas chercher à utiliser une librairie java, pas sûr que je puisse facilement l'importer dans l'outil.

    j'ai défini pour d'autres projets des fonctions java que je peux utiliser dans mes mappings Tibco. Notamment, celle-ci que j'ai recherché à utiliser.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    public static String regexsubst(String input, String patt, String to)
      {
        Pattern p = Pattern.compile(patt);
        Matcher m = p.matcher(input);
        return m.replaceAll(to);
      }
    Je viens de tester ta solution CosmoKnacki, ça fonctionne sauf dans un cas. Celui que tu as identifié dans ton message, la présence d'un ", échappé avec ""

    J'ai essayé de modifier ta regex...mais je n'ai pas le niveau je crois . Elle est quand même un peu compliqué aussi

    pour une ligne contenant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    data1,"data2a ""data2b"" data2c",data3,"data4a,data4b"
    j'obtiens:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    data1,data2a data2b data2c;data3,data4a;data4b
    Aurais tu une solution pour gérer également ce cas stp?

  6. #6
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Et ça ne fonctionne pas non plus pour ce cas : data1,"data2a","data3a,data3b",data4, le résultat étant : data1,"data2a;data3a,data3b;data4.
    Pour la " qui traine, on peut le résoudre simplement par (?:\\G(?<=[^\"])|\"([^\",]*)),?([^\",]*)\"?", mais ça ne fonctionne pas avec les "".
    Pour la ;, je ne vois pas comment procéder, vu qu'on l'a dans la chaine de remplacement, a part procéder en 2 passes (une première regex : (\")([^,]*)(\"), en remplacant par $2).
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  7. #7
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Comme tu le constate rapidement, fait évoluer des regexp pour faire ce que tu veux, ce n'est pas un cinécure. Pourquoi ne pas faire ça dans une petit méthode vite fait? C'est facile à adapter pour les cas que tu n'avais pas prévu ou pour d'autres trucs tordus.

    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
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    public class Main {
     
      private static final char REPLACEMENT_CHAR = ';';
      private static final char SEPARATOR_CHAR = ',';
      private static final char QUOTE_MARKER = '"';
     
      public static String clear(String toClear) {
        char[] content = toClear.toCharArray();
        char[] result = new char[content.length];
     
        boolean inQuote = false;
        int j = 0;
        for (int i = 0; i < content.length; i++) {
          char c = content[i];
          if (inQuote) {
            if (c == SEPARATOR_CHAR) {
              result[j++] = REPLACEMENT_CHAR;
              continue;
            } else if (c == QUOTE_MARKER) {
              if (i < content.length - 1 && content[i + 1] == QUOTE_MARKER) {
                // it's a quote in a quote
                i++;
                result[j++] = QUOTE_MARKER;
                continue;
              } else { // quote end
                inQuote = false;
                continue;
              }
            }
          } else if (c == QUOTE_MARKER) { // quote start;
            inQuote = true;
            continue;
          }
          result[j++] = c;
        }
        return new String(result, 0, j);
      }
     
      public static void main(String[] args) {
        String toEscape = "data1,\"data2a \"\"data2b\"\" data2c\",data3,\"data4a,data4b\"";
        String toEscape2 = "\"data1,\"data2a\",\"data3a,data3b\",data4,";
        System.out.println(toEscape + " echappe donne " + clear(toEscape));
        System.out.println(toEscape2 + " echappe donne " + clear(toEscape2));
      }
     
    }

  8. #8
    Nouveau membre du Club
    Inscrit en
    Février 2006
    Messages
    49
    Détails du profil
    Informations personnelles :
    Âge : 38

    Informations forums :
    Inscription : Février 2006
    Messages : 49
    Points : 33
    Points
    33
    Par défaut
    "data1,"data2a","data3a,data3b",data4
    je n'ai jamais ce cas à première vue...

    celui-ci existe, mais il semble fonctionner:
    data1,"data2a","data3a,data3b",data4

    c'est vraiment ça qui me pose problème

    data1,"data2a ""data2b"" data2c",data3,"data4a,data4b"

  9. #9
    Membre chevronné
    Avatar de eulbobo
    Homme Profil pro
    Développeur Java
    Inscrit en
    Novembre 2003
    Messages
    786
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Novembre 2003
    Messages : 786
    Points : 1 993
    Points
    1 993
    Par défaut
    Le vrai problème c'est que le "format" de ton fichier de base est tout pourri et ne respecte pas vraiment de norme de délimitation des champs.
    Il n'y a aucun moyen de résoudre ce problème à la source plutôt que d'essayer de trouver une solution qui tentera de corriger un format incorrect et potentiellement variable au delà de tes espérances?
    Je ne suis pas mort, j'ai du travail !

  10. #10
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par GregHory Voir le message
    "data1,"data2a","data3a,data3b",data4
    je n'ai jamais ce cas à première vue...

    celui-ci existe, mais il semble fonctionner:
    data1,"data2a","data3a,data3b",data4
    C'est bien de ce dernier cas, donc je parle, et moi, si j'exécute ça en Java (8), ça ne fonctionne pas

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public static void main(String[] args) {
    	System.out.println(replaceComma("data1,\"data2a\",\"data3a,data3b\",data4"));
    }
     
    public static String replaceComma(String s) {	
     
       Pattern p = Pattern.compile("(?:\\G(?<=[^\"])|\"([^\",]*)),([^\",]*)\"?");
       return p.matcher(s).replaceAll("$1;$2");
     
    }
    Donne
    data1,"data2a;data3a,data3b;data4
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  11. #11
    Nouveau membre du Club
    Inscrit en
    Février 2006
    Messages
    49
    Détails du profil
    Informations personnelles :
    Âge : 38

    Informations forums :
    Inscription : Février 2006
    Messages : 49
    Points : 33
    Points
    33
    Par défaut
    effectivement, tu as raison... ça ne fonctionne pas dans ce cas la non plus...grrrrr

    Non je fichier source provient de SAP Sourcing, je n'ai pas la main dessus.

    les règles du fichier source sont les suivantes:
    - les colonnes sont séparées par des virgules.
    - si les données d'une colonne contiennent des virgules, la colonne est mis entre " => colPrec,"donnée, donnée",colSuiv
    - si les données contiennent des " alors, la colonne est mise entre " et ceux d'origines sont doublé "" => colPrec,"donnée, ""donnée"", donnée",colSuiv


  12. #12
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    La méthode de @Tchize_ reste en effet la plus simple, et la plus simplement évolutive...
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  13. #13
    Nouveau membre du Club
    Inscrit en
    Février 2006
    Messages
    49
    Détails du profil
    Informations personnelles :
    Âge : 38

    Informations forums :
    Inscription : Février 2006
    Messages : 49
    Points : 33
    Points
    33
    Par défaut
    effectivement,

    je vais abandonner l'idée de faire ça avec des regex trop compliquée pour moi.
    j'ajoute la fonction de Tchize_ dans ma librairie et je teste

  14. #14
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 842
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 842
    Points : 6 522
    Points
    6 522
    Par défaut
    Effectivement, difficile de battre une machine à états bien écrite sur un langage compilé (plus ou moins). Même avec une pattern optimisée qui gère les quotes échappés et les items sans virgule, (un bonheur de ~190 caractères sans espaces que je vous épargne), il faut faire un deuxième passage pour enlever les quotes surnuméraires. Le résultat reste honorable cela dit (~7 fois le temps de la machine à états).
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [RegEx] Regex avec virgule dans double quotes
    Par LeHibou2 dans le forum Langage
    Réponses: 2
    Dernier message: 16/12/2012, 21h16
  2. [RegEx] Regex pour detecter les virgules non entre guillemets
    Par calitom dans le forum Langage
    Réponses: 8
    Dernier message: 06/09/2010, 15h38
  3. [debutant]toutes les valeurs entre cotes ?
    Par goony dans le forum Langage SQL
    Réponses: 4
    Dernier message: 03/04/2006, 11h13
  4. [VB6]sortir toutes les dates entre deux dates
    Par AlfiQue dans le forum VB 6 et antérieur
    Réponses: 9
    Dernier message: 20/02/2006, 20h09
  5. Borland C++ 5.5 remplacer toutes les occurences
    Par cdelamarre dans le forum Autres éditeurs
    Réponses: 2
    Dernier message: 30/11/2005, 13h23

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