Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
2858 connectés 

  FORUM HardWare.fr
  Programmation
  Perl

  Concatenation lignes

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

Concatenation lignes

n°2270924
supermalla​in
Posté le 07-12-2015 à 11:08:32  profilanswer
 

Bonjour à tous,
 
Je débute en perl et je n'arrive pas à concaténer des lignes.
Je m'explique, j'ai 1 seul fichier texte constitué ainsi :  
 

Code :
  1. ANGLAIS|BOBIN|BOBIN|JEAN|28/10/1966|CERT|RENNES|Mention Complementaire|Non|N|
  2. ANGLAIS|BOBIN|BOBIN|JEAN|28/10/1966|CERT|RENNES|Ancienneté dans le poste|3|N|
  3. ANGLAIS|BOBIN|BOBIN|JEAN|28/10/1966|CERT|RENNES|Ancienneté de service|8|N|
  4. LET MODERN|LOUVOIS|LOUVOIS|JOSE|21/11/1984|CERT|NANTES|Enfants à charge|1|N|
  5. LET MODERN|LOUVOIS|LOUVOIS|JOSE|21/11/1984|CERT|NANTES|Ancienneté dans le poste|1|N|
  6. LET MODERN|LOUVOIS|LOUVOIS|JOSE|21/11/1984|CERT|NANTES|Mention Complementaire|Non|N|
  7. LET MODERN|LOUVOIS|LOUVOIS|JOSE|21/11/1984|CERT|NANTES|Ancienneté de service|7|N|


 
Je cherche à faire un test sur la ligne pour donner le resultat suivant :  
 

Code :
  1. ANGLAIS|BOBIN|BOBIN|JEAN|28/10/1966|CERT|RENNES|Mention Complementaire|Non|Ancienneté dans le poste|3|Ancienneté de service|8|N|
  2. LET MODERN|LOUVOIS|LOUVOIS|JOSE|21/11/1984|CERT|NANTES|Enfants à charge|1|Ancienneté dans le poste|1|Mention Complementaire|Non|Ancienneté de service|7|N|


 
Pour l'instant, voici ce que j'ai réussis à faire mais qui ne fonctionne pas:  
 

Code :
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. open(FICHIER, '< C:\Users\mon_fichier.txt') || die;
  5. while (my $whole_line = <FICHIER> ) {
  6. my ($discipline,$nom,$nom_patro,$prenom,$datenaissance,$grade, $ville, $bareme) = split(/\|/, $whole_line);
  7.               print "$discipline ";
  8.      
  9. }
  10. close FICHIER;


 
Après plusieurs tentative de tests, je n'arrive pas à écrire :
 
 Dans le fichier,  SI disciplineligne1 & nomligne1 & prenomigne1 = disciplineligne2 & nomligne2 & prenomigne2 ALORS...
 
 
Merci d'avance pour votre aide.


Message édité par supermallain le 07-12-2015 à 13:22:46
mood
Publicité
Posté le 07-12-2015 à 11:08:32  profilanswer
 

n°2270940
gilou
Modérateur
Modzilla
Posté le 07-12-2015 à 12:59:31  profilanswer
 

Faudrait peut être faire l'effort de donner un fichier de test valide.
LET MODERN|LOUVOIS|LOUVOIS|JOSE|21/11/1984|CERT|NANTES|Ancienneté dans le poste|N|
Alors que ça devrait être
LET MODERN|LOUVOIS|LOUVOIS|JOSE|21/11/1984|CERT|NANTES|Ancienneté dans le poste|1|N|
au vu de ta sortie désirée
 
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°2270947
supermalla​in
Posté le 07-12-2015 à 13:23:18  profilanswer
 

gilou a écrit :

Faudrait peut être faire l'effort de donner un fichier de test valide.
LET MODERN|LOUVOIS|LOUVOIS|JOSE|21/11/1984|CERT|NANTES|Ancienneté dans le poste|N|
Alors que ça devrait être
LET MODERN|LOUVOIS|LOUVOIS|JOSE|21/11/1984|CERT|NANTES|Ancienneté dans le poste|1|N|
au vu de ta sortie désirée
 
A+,


 
Autant pour moi. C'est corrigé.

n°2270958
gilou
Modérateur
Modzilla
Posté le 07-12-2015 à 14:23:04  profilanswer
 

Code :
  1. #!/usr/bin/perl
  2. use Modern::Perl;
  3. use autodie;
  4.  
  5. my $re = qr{(?:[^|]+\|)};
  6. my ($prev_start, $prev_end);
  7. open my $fh, '<', 'C:\Users\mon_fichier.txt';
  8. while (<$fh> ) {
  9.  chop;
  10.  if (/^(?<start>$re{7})(?<mid>$re{2})(?<end>$re)$/) {
  11.    if ($. == 1) {
  12.      print $+{start}, $+{mid};
  13.      ($prev_start, $prev_end) = ($+{start}, $+{end});
  14.    }
  15.    else {
  16.      if ($prev_start eq $+{start}) {
  17.         print $+{mid};
  18.      }
  19.      else {
  20.         print $prev_end, "\n", $+{start}, $+{mid};
  21.         ($prev_start, $prev_end) = ($+{start}, $+{end});
  22.      }
  23.    }
  24.  }
  25. }
  26. close $fh;
  27. if ($prev_end) {
  28.    print $prev_end, "\n";
  29. }


 
La ligne est constituée de 10 suites d'un truc formé de texte suivi d'un |. Je colle un tel truc dans une regexp
my $re = qr{(?:[^|]+\|)};
pour réutilisation sous une forme plus lisible. (?:...) est un non-capturing group, qui ne colle pas automatiquement ce qui matche dans une variable.
Bon, on parse ligne a ligne. Si on a une ligne de la forme attendue:
if (/^(?<start>$re{7})(?<mid>$re{2})(?<end>$re)$/) {
(?<nom>...) est un named-capturing group, qui colle ce qui matche dans une variable de nom $+{nom}
Ici, je mets les 7 premiers trucs (éventuellement communs a plusieurs lignes) dans une variable $+{start}, idem pour le truc final, dans $+{end}, et les 2 trucs variables entre les deux seront collés dans $+{mid}.
Si c'est la première ligne
if ($. == 1) {
On imprime le début et le milieu (pas la fin car il y aura peut être d'autres milieux à ajouter)
print $+{start}, $+{mid};
et on stocke le début et la fin courante
($prev_start, $prev_end) = ($+{start}, $+{end});
Sinon, si c'est pas la première ligne
Si le début est le même que celui de la ligne précédente
if ($prev_start eq $+{start}) {
On imprime le nouveau milieu
print $+{mid};
Sinon, si le début est différent de celui de la ligne précédente
On a une nouvelle ligne donc on imprime la fin de la ligne précédente, puis le début et le milieu de la nouvelle ligne en cours
print $prev_end, "\n", $+{start}, $+{mid};
Et on stocke le nouveau début et la nouvelle fin
($prev_start, $prev_end) = ($+{start}, $+{end});
En fin de fichier, on imprime la fin de la dernière ligne lue, s'il y en a une
if ($prev_end) { print $prev_end, "\n"; }
et voila.
 
Note:
Si on peut avoir des champs vide, et donc un || dans les données, remplacer la regexp
my $re = qr{(?:[^|]+\|)};  
par
my $re = qr{(?:[^|]*\|)};  
 
Il y avait aussi moyen de passer par des arrays, ou plutôt par des hashes, mais pour juste cette fusion de lignes, c'était un peu le coup de l'enclume pour craser une mouche. Sinon, une utilisation de Text::CSV aurait pu être pratique.
ou bien faire un
my @fields = qw(discipline nom nom_patro prenom datenaissance grade ville bareme bareme_val yn);
my %data;
...
@data{@fields} = split /\|/;
qui aurait collé les valeurs lues dans le hash suivant l'ordre des clés prises dans @fields.
C'est un idiome perl bien pratique.
 
A+,


Message édité par gilou le 07-12-2015 à 14:40:34

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°2270969
supermalla​in
Posté le 07-12-2015 à 15:47:41  profilanswer
 

Un GRAND MERCI ! Trop fort ! ça fonctionne très bien  :bounce:  
 
Pour aller plus loin, j'aimerai savoir ce que je dois modifier pour traiter des lignes avec 19 valeurs comme ceci :  
 

Code :
  1. ANGLAIS|BOBIN|BOBIN|JEAN|28/10/1966|CERT. CL N|MONTPEL.|Mention Complementaire|Non||O| | | |||||N|


 
Vu que j'ai en effet des valeurs vides, j'ai tenté de modifier comme tu me l'a dis la regex : my $re = qr{(?:[^|]*\|)};
Mais j'ai une erreur en sortie...

n°2270972
gilou
Modérateur
Modzilla
Posté le 07-12-2015 à 15:59:51  profilanswer
 

my $re = qr{(?:[^|]*\|)};
oui,
et il faut modifier
if (/^(?<start>$re{7})(?<mid>$re{2})(?<end>$re)$/) {
en fonction de ce qui sera commun ou non.
A vue de nez, ce pourrait être
if (/^(?<start>$re{7})(?<mid>$re{2})(?<end>$re{10})$/) {
mais je ne connais pas vos données.
Ici, j'ai supposé que les 10 derniers champs étaient eux aussi communs.
Je suppose que vous n'avez pas des lignes à 10 et 19 champs dans le même fichier.
 
A+,


Message édité par gilou le 07-12-2015 à 16:02:12

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°2270977
supermalla​in
Posté le 07-12-2015 à 16:22:32  profilanswer
 

C'est ce que j'ai fais aussi pour : if (/^(?<start>$re{7})(?<mid>$re{2})(?<end>$re{10})$/) {
 
J'ai testé de ça me renvoie le résultat suivant :  
 

Code :
  1. ANGLAIS|BOBIN|BOBIN|JEAN|28/10/1966|CERT|RENNES|Mention Complementaire|Non|Ancienneté dans le poste|3||O| | | |||||N|


il manque :  
 

Code :
  1. Ancienneté de service|8|

après "|3|".
 
Apres la valeur "|O|", les données sont différentes, la valeur entre 2 "|" peut être vide ou pas...  
Toujours est-il qu'on aura toujours 19 valeurs entre les "|".

n°2271001
gilou
Modérateur
Modzilla
Posté le 07-12-2015 à 20:04:55  profilanswer
 

Moi, a partir de vos données, j'ai fait le fichier de test suivant:

ANGLAIS|BOBIN|BOBIN|JEAN|28/10/1966|CERT. CL N|MONTPEL.|Mention Complementaire|Non||O| | | |||||N|
ANGLAIS|BOBIN|BOBIN|JEAN|28/10/1966|CERT. CL N|MONTPEL.|Ancienneté dans le poste|3||O| | | |||||N|
ANGLAIS|BOBIN|BOBIN|JEAN|28/10/1966|CERT. CL N|MONTPEL.|Ancienneté de service|8||O| | | |||||N|


et le code que je vous ai donné,  

Code :
  1. #!/usr/bin/perl
  2. use Modern::Perl;
  3. use autodie;
  4.  
  5. open my $fh, '<', 'ccl.txt';
  6. my $re = qr{(?:[^|]*\|)};
  7. my ($prev_start, $prev_end);
  8. while (<$fh> ) {
  9.  chop;
  10.  if (/^(?<start>$re{7})(?<mid>$re{2})(?<end>$re{10})$/) {
  11.    if ($. == 1) {
  12.      print $+{start}, $+{mid};
  13.      ($prev_start, $prev_end) = ($+{start}, $+{end});
  14.    }
  15.    else {
  16.      if ($prev_start eq $+{start}) {
  17.     print $+{mid};
  18.      }
  19.      else {
  20.     print $prev_end, "\n", $+{start}, $+{mid};
  21.     ($prev_start, $prev_end) = ($+{start}, $+{end});
  22.      }
  23.    }
  24.  }
  25. }
  26. print $prev_end, "\n";
  27. close $fh;


il me donne ceci en sortie:

ANGLAIS|BOBIN|BOBIN|JEAN|28/10/1966|CERT. CL N|MONTPEL.|Mention Complementaire|Non|Ancienneté dans le poste|3|Ancienneté de service|8||O| | | |||||N|

[:souk]  
 
EDIT: Je subodore que votre 3e ligne n'avait pas 19 champs, et donc qu'elle n'a pas été prise en compte.
 
A+,


Message édité par gilou le 07-12-2015 à 20:08:52

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --

Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  Perl

  Concatenation lignes

 

Sujets relatifs
[Perl] simplifier ma regex[SQL] Select un nbre max de données = selectionner une ligne sur n.
[PERL] CGI retourner un code erreurComment protéger mes vidéos html5 en ligne
Concatenation de caractères[Resolu]Supprimer la ligne vide
e voudrais lancer plusieurs script Perl à partir d'un autre script Per[Cobol] Concaténation de chaînes
Suppression de ligne dans un fichierfaire un site marchand/boutique en ligne
Plus de sujets relatifs à : Concatenation lignes


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR