Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Remplacement d'éléments d'une liste

3 réponses
Avatar
titof92
Bonjour,

J'ai un fichier de donn=E9e au format CSV (avec des caract=E8res ; en
guise de s=E9parateurs de valeurs) que je lis en s=E9quentiel. En fait, je
voudrais remplacer le code dossier a figurant en 2e =E9l=E9ment dans
l'extrait ci-dessous par le code dossier b, disponible dans ma table
de hachage d'une part, remplacer les dates apparaissant sur chaque en
ligne, en changeant le format pour qu'elles apparaissent en format
AAAAMMJJ au lieu de JJ/MM/AAAA (en =E9vitant toutefois d'utiliser la
fonction S/elt1/elt2/, mais en recourant plut=F4t =E0 une it=E9ration qui
parcourt =E9l=E9gamment chaque =E9l=E9ment de @tabligne (r=E9sultat du spli=
t ma
ligne)...

Je pense qu'il y a s=FBrement moyen, =E9tant donn=E9 que l'indice le plus
faible est 0 (pour le max qui n'est autres que la taille de la liste,
je ne sais pas s'il y a une variable standard Perl d=E9j=E0 disponible
pour l'occaz ...)

Extrait de mon fichier de donn=E9es:
233;113456671111;10/12/2011;10/12/2011;M. DUPONT;ERVI;PARIS
456;908289877378:08/05/2001;17;04;2002;Melle DUPRE
Sylvie;ETTY;TOULOUSE
567;356536565365;01/03/1979;09/03/1983;Mme ZANNI C=E9line;ELSI;SAUMUR

Dans le code qui suit, listeDossiers est une table de hachage dans
laquelle je stocke le r=E9sultat d'une requ=EAte qui =E9tablit la
correspondance entre des codes dossiers a et des codes dossiers b.

...
# Lecture en s=E9quentiel du fichier re=E7u
while ($ligne =3D <FIC_IN>) {

# Prise en compte de la ligne avec separateurs CSV (;)
@tabligne =3D split(';', $ligne);

print "Ligne en entr=E9e : $ligne \n";

# Lecture de toutes les lignes sauf HDR/TRL
if (($ligne ne '') && ($ligne !~ m!^[Hh][Dd][Rr]|^[Tt][Rr][Ll]! )) {
chomp $ligne;

$cdossier_a=3D$tabligne[2];

# Recherche du code dossier b dans la requ=EAte de correspondance
cdossier_b-> cdossier_a
$cdossier_b=3D$listeDossiers{$cdossier_a};

if (!exists($listeDossiers{$cdossier_a})) {
print FIC_LOG "Le dossier $cdossier_a n\'existe pas \!\n";
} else {
$ligne=3D~ s/$cdossier_a/$cdossier_b/;
print FIC_OUT "$ligne\n";
}

}

print "Ligne en sortie : $ligne \n\n" ;

...


Merci beaucoup.

3 réponses

Avatar
Jean-Louis Morel
Le 21/12/2011 22:39, titof92 a écrit :

J'ai un fichier de donnée au format CSV (avec des caractères ; en
guise de séparateurs de valeurs) que je lis en séquentiel. En fait, je
voudrais remplacer le code dossier a figurant en 2e élément dans
l'extrait ci-dessous par le code dossier b, disponible dans ma table
de hachage d'une part, remplacer les dates apparaissant sur chaque en
ligne, en changeant le format pour qu'elles apparaissent en format
AAAAMMJJ au lieu de JJ/MM/AAAA (en évitant toutefois d'utiliser la
fonction S/elt1/elt2/, mais en recourant plutôt à une itération qui
parcourt élégamment chaque élément de @tabligne (résultat du split ma
ligne)...

Je pense qu'il y a sûrement moyen, étant donné que l'indice le plus
faible est 0 (pour le max qui n'est autres que la taille de la liste,
je ne sais pas s'il y a une variable standard Perl déjà disponible
pour l'occaz ...)

Extrait de mon fichier de données:
233;113456671111;10/12/2011;10/12/2011;M. DUPONT;ERVI;PARIS
456;908289877378:08/05/2001;17;04;2002;Melle DUPRE
Sylvie;ETTY;TOULOUSE
567;356536565365;01/03/1979;09/03/1983;Mme ZANNI Céline;ELSI;SAUMUR




Je ne suis pas sûr d'avoir compris la question (et comme personne
ne répond, je suppose que je ne suis pas le seul dans cette situation).

D'abord, si vous parcourez votre tableau @tabligne avec un indice
variant de 0 à $#tabligne avec une boucle for ce n'est pas élégant
pour un programmeur Perl (ça fait trop programmeur C... ;-)

Pourquoi ne voulez-vous pas convertir directement les dates dans
la chaîne $ligne ?

$ligne =~ s!(dd)/(dd)/(dddd)!$3$2$1!g;

Ou bien, si vous voulez convertir uniquement les dates comprises entre
deux points-virgules (donc pas de date en début et fin de ligne) :

$ligne =~ s!;(dd)/(dd)/(dddd);!;$3$2$1;!g;

HTH

--
JL
http://www.bribes.org/perl
Avatar
Azra
Bonjour,
je suis pas certain de comprendre toutes les contraintes du probleme non
plus. Voici une idee de solution pour l'autre probleme [plus simple].

Si vous voulez absolument utiliser split pour modifier la ligne, il est
surement bon d'utiliser un join une fois que vous avez fini de modifier
la ligne et que vous voulez la ``reformer'' en une ligne CSV.
Par ailleurs, il est alors bon de faire les modifications utilisant les
regexps sur la ligne complete soit avant le split soit apres le join !

Ainsi dans votre code
$ligne=~ s/$cdossier_a/$cdossier_b/; # peut -a priori- matcher le premier
# champ de la ligne et le remplacer !
# il faudrait specifier que cdossier_a se trouve
# dans le 2e champ avec s/;$cdossier_a/$cdb/; par
# ex.
devrait se faire remplacer par
$tabligne[2] = $cdossier_b;
$ligne = join ';', @tabligne;


non ?

enfin il y a des chances pour que
$cdossier_b=$listeDossiers{$cdossier_a};
renvoie des warnings [bien penser a utiliser use warnings en tete de
script]
il vaut mieux mettre cette ligne dans votre structure if/else non ???

HTH2
azra

titof92 wrote:

Bonjour,

J'ai un fichier de donnée au format CSV (avec des caractères ; en guise
de séparateurs de valeurs) que je lis en séquentiel. En fait, je
voudrais remplacer le code dossier a figurant en 2e élément dans
l'extrait ci-dessous par le code dossier b, [...]

# Lecture de toutes les lignes sauf HDR/TRL if (($ligne ne '') &&
($ligne !~ m!^[Hh][Dd][Rr]|^[Tt][Rr][Ll]! )) {
chomp $ligne;

$cdossier_a=$tabligne[2];

# Recherche du code dossier b dans la requête de


correspondance
cdossier_b-> cdossier_a
$cdossier_b=$listeDossiers{$cdossier_a};

if (!exists($listeDossiers{$cdossier_a})) {
print FIC_LOG "Le dossier $cdossier_a n'existe


pas !n";
} else {
$ligne=~ s/$cdossier_a/$cdossier_b/;
print FIC_OUT "$lignen";
}

}

print "Ligne en sortie : $ligne nn" ;

...


Merci beaucoup.
Avatar
Paul Gaborit
À (at) Wed, 21 Dec 2011 13:39:24 -0800 (PST),
titof92 écrivait (wrote):

J'ai un fichier de donnée au format CSV (avec des caractères ; en
guise de séparateurs de valeurs) que je lis en séquentiel.



Au lieu de (mal) réinventer la roue, vous feriez mieux d'utiliser l'un
des deux modules Text::CSV ou Text::CSV_XS. Ils vous garantissent la
lecture et l'écriture correctes des fichiers CSV. C'est une chose plus
difficile à faire qu'il n'y paraît...

Vous pouvez aussi jeter un oeil à DBI et DBD::CSV qui permettent de
manipuler avec des requêtes SQL standard un ensemble de fichiers CSV
considéré comme une base de données.

--
Paul Gaborit - <http://perso.mines-albi.fr/~gaborit/>
Perl en français - <http://perl.mines-albi.fr/>