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

C# Discussion :

fusionner des lignes fichier .txt [Débutant]


Sujet :

C#

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    1 051
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Hautes Pyrénées (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 051
    Par défaut fusionner des lignes fichier .txt
    Bonjour,

    Je viens solliciter votre aide car je manque de méthodologie pour un problème que je rencontre.

    Je dois effectuer une fusion de ligne identique dans un fichier d'entrée .xml

    Le fichier XML ne porte que l'extension (car dedans c'est plus un fichier csv en réalité avec des ; pour délimiter chaque paramètre). Voici un exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    PLNE-CPT;OUVDEF;20111103;LC003-2;LC003;09;TOULOUSE;RTLS;TOULOUSE;;;;;;;;;;;;;;;;;;;;;;;;;;
    PLNE-CPT;OUVDEF;20111103;LC003-2;;09;TOULOUSE;RTLS;TOULOUSE;Oui;;;;;;;;;;;;;;;;;;;;;;;;;
    PLNE-CPT;OUVDEF;20111103;LC003-2;;09;TOULOUSE;RTLS;TOULOUSE;;;PTZ;;;;;;;;;;;;;;;;;;;;;;;
    PLNE-CPT;OUVDEF;20111103;LC003-2;;09;TOULOUSE;RTLS;TOULOUSE;;Relevé jour. données horaires;;;;;;;;;;;;;;;;;;;;;;;;
    Comme je travaille avec biztalk, je ne peux pas changer l'extension.

    En fait, j'aurais besoin de fusionner certaines lignes. Pour cela je dois comparer deux champs de chaque lignes pour regarder ceux qui sont identiques, et ainsi fusionner ces deux champs.

    Exemple (fichier avant) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    PLNE-CPT;OUVDEF;20111103;LC003-2;;09;TOULOUSE;RTLS;TOULOUSE;Oui;;;;;;;;;;;;;;;;;;;;;;;;;
    PLNE-CPT;OUVDEF;20111103;LC003-2;;09;TOULOUSE;RTLS;TOULOUSE;;;PTZ;;;;;;;;;;;;;;;;;;;;;;;
    Après :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    PLNE-CPT;OUVDEF;20111103;LC003-2;;09;TOULOUSE;RTLS;TOULOUSE;Oui;;PTZ;;;;;;;;;;;;;;;;;;;;;;;
    En fusionnant, chaque paramètre doit garder sa place respective. Pour fusionner, je dois utiliser le 2eme et 3eme paramètre de chaque ligne.

    J'ai essayé de chercher, en travaillant avec un dataset, puis requête linq, mais je doute à un résultat fiable et rapide. Puis en lisant ligne par ligne .. mais je finis avec des boucles de partout, et j'ai peur que ca soit pas fiable du tout..

    Auriez-vous une méthode pour m'aiguiller pour trouver une solution ?

    Merci d'avance !

  2. #2
    Membre Expert Avatar de Er3van
    Homme Profil pro
    Architecte Logiciel
    Inscrit en
    Avril 2008
    Messages
    1 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Architecte Logiciel
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2008
    Messages : 1 430
    Par défaut
    Nécessité de sérialiser ?

    Quel champ te permet d'établir l'égalité ?
    Est-il possible que dans certains cas il y ait conflit ? (par exemple, pour une même valeur tu as "Toto", "Tata", que prends-tu ?

    Avec quelque chose du genre, tu peux avoir le résultat escompté :

    Code c# : 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
     
    public void DoSomething(String message)
            {
                Dictionary<String, String> dictionary = new Dictionary<string, string>();
                string line;
                char[] separator = { ';' };
                int keyPosition = 3;
                string key = null;
     
                using (StringReader stringReader = new StringReader(message))
                {
                    // Creation du dictionnaire
                    while ((line = stringReader.ReadLine()) != null)
                    {
                        try
                        {
                            key = line.Split(separator).GetValue(keyPosition).ToString();
                            dictionary.Add(key, line);
                        }
                        catch (ArgumentException)
                        {
                            // La clé existe déjà : le cas que tu veux !
     
                            // Récupération de l'ancienne valeur
                            KeyValuePair<String,String> val = dictionary.Single(k => k.Key == key);
     
                            // Merge
                            String newVal = MergeLines(val.Value, line);
     
                            // Remplacement de la valeur
                            dictionary.Remove(key);
                            dictionary.Add(key, newVal);
                        }
                        catch (Exception) { throw; }
                    }                
                }
            }
     
            private string MergeLines(string p, string line)
            {
                throw new NotImplementedException();
            }

    C'est pas optimal, faudrait peut-être utiliser une liste de paire clé/valeur plutôt qu'un dictionnaire pour simplifier l'update.., mais c'est un début pour te donner une piste.

  3. #3
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Il manque une info cruciale : selon quel critère décides-tu que 2 lignes doivent être fusionnées ? Y a-t-il un champ qui sert d'identifiant (ou éventuellement plusieurs champs) ?

    En supposant que c'est les 4 premiers champs qui servent d'identifiants (ça semble être le cas dans ton exemple), on va regrouper par exemple tous les enregistrements qui ont par exemple "PLNE-CPT;OUVDEF;20111103;LC003-2" dans ces champs.

    Ensuite, pour chaque groupe d'enregistrements, il faudrait savoir comment tu gères les conflits, comme mentionné par Er3van. Je vais supposer qu'on gère ça de la façon la plus simple possible : pour un champ donné, on prend la première valeur non vide

    Avec Linq, on peut facilement grouper les lignes par identifiant comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
        string path = @"E:\tmp\data.csv";
        string[] lines = File.ReadAllLines(path);
     
        var groups =
            from line in lines
            let values = line.Split(';')
            group values by new
            {
                Key1 = values[0],
                Key2 = values[1],
                Key3 = values[2],
                Key4 = values[3],
            };
    (je te laisse le soin de trouver des noms plus pertinents que Key1, Key2 etc, mais moi je sais pas à quoi correspondent les valeurs ; de toutes façons ça n'a pas d'importance puisqu'on ne réutilise pas ces valeurs par la suite)

    On se retrouve donc avec une liste de groupes d'enregistrements, chaque enregistrement étant sous la forme d'un tableau de string. Ensuite il faut voir comment fusionner les enregistrements d'un même groupe. Pour ça, le plus simple est d'écrire une méthode dédiée, où on crée un tableau de la bonne taille qu'on remplit en parcourant les enregistrements. Si une valeur est déjà renseignée, on la laisse, sinon on prend celle de l'enregistrement en cours.

    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
    string[] MergeRecords(IEnumerable<string[]> records)
    {
        string[] firstRecord = records.First();
        string[] finalRecord = new string[firstRecord.Length];
        foreach (var record in records)
        {
            for (int i = 0; i < finalRecord.Length; i++)
            {
                if (string.IsNullOrEmpty(finalRecord[i]) &&
                    !string.IsNullOrEmpty(record[i]))
                {
                    finalRecord[i] = record[i];
                }
            }
        }
        return finalRecord;
    }
    On peut maintenant générer un seul enregistrement pour chaque groupe :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
        var mergedRecords =
            from g in groups
            select MergeRecords(g);
    On peut même simplifier un peu :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    var mergedRecords = groups.Select(MergeRecords);
    On obtient une liste d'enregistrements, qui sont toujours sous forme de tableaux de strings ; il ne reste plus qu'à regénérer les lignes en séparant les valeurs par des ";", à l'aide de String.Join, et à les écrire dans le nouveau fichier :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    using (var writer = new StreamWriter(outputPath))
    {
        foreach (var rec in mergedRecords)
        {
            writer.WriteLine (String.Join(";", rec));
        }
    }
    Résultat pour les 4 lignes de ton exemple :

    PLNE-CPT;OUVDEF;20111103;LC003-2;LC003;09;TOULOUSE;RTLS;TOULOUSE;Oui;Relevé jour. données horaires;PTZ;;;;;;;;;;;;;;;;;;;;;;;

  4. #4
    Membre Expert Avatar de Er3van
    Homme Profil pro
    Architecte Logiciel
    Inscrit en
    Avril 2008
    Messages
    1 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Architecte Logiciel
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2008
    Messages : 1 430
    Par défaut
    Pour compléter :

    - Je suis parti de l'hypothèse arbitraire que c'est le 3e champ qui permettait d'établir l'égalité dans mon exemple, s'il faut aditionner plusieurs contraintes, l'utilisation du dictionnaire ne marcherait pas tel quel, il faudrait utiliser une clé qui concatène les contraintes.

    - Si le cas où les valeurs "à fusionner" est courant (> 10% des cas), la méthode de TomLev sera plus adaptée et plus performante.

    - Si cela représente qu'un pourcentage faible, je trouve ça plus simple de gérer ça comme une exception, mais c'est qu'une question de préférence.


    Question bonus : Que fais-tu de ces données après traitement ?

  5. #5
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Citation Envoyé par Er3van Voir le message
    - Si cela représente qu'un pourcentage faible, je trouve ça plus simple de gérer ça comme une exception, mais c'est qu'une question de préférence.
    Comme un cas exceptionnel si tu veux, mais pas comme une exception... c'est une mauvaise pratique d'intercepter une exception quand tu peux facilement éviter qu'elle se produise. En l'occurrence il suffit de vérifier si la clé est déjà dans le dictionnaire...

  6. #6
    Membre Expert Avatar de Er3van
    Homme Profil pro
    Architecte Logiciel
    Inscrit en
    Avril 2008
    Messages
    1 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Architecte Logiciel
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2008
    Messages : 1 430
    Par défaut
    C'est la différence entre la langue française :
    - Exception : cas qui arrive rarement

    ...et le C# :
    - Exception : cas qui ne devrait pas arriver

    Mais sur le principe je suis d'accord avec toi ! Mais bon, mettre un if c'est pas le plus compliqué.

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

Discussions similaires

  1. Extraire des lignes fichiers txt
    Par alkaz dans le forum C#
    Réponses: 4
    Dernier message: 27/05/2015, 12h01
  2. Réponses: 2
    Dernier message: 06/06/2008, 16h49
  3. [SQL-VBA]fusionner des lignes
    Par shagun dans le forum Requêtes et SQL.
    Réponses: 42
    Dernier message: 13/04/2007, 13h37
  4. [BATCH]Récup 2nd ligne fichier txt
    Par guigui11 dans le forum Windows
    Réponses: 2
    Dernier message: 28/09/2006, 17h34
  5. Effacer dernière ligne fichier txt
    Par soulryo dans le forum VB 6 et antérieur
    Réponses: 3
    Dernier message: 25/09/2006, 22h05

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