Comment maintenir le contenu d'une variable?
Résoluartagon7 Messages postés 417 Date d'inscription Statut Membre Dernière intervention -
Bonjour,
Je fais le traitement de fichiers en plusieurs étapes. J'ai réussi, jusqu'à maintenant, toutes les étapes, sauf une. J'ai rédigé un programme mais ça ne fonctionne pas.
Le programme doit lire chaque ligne d'un fichier et réécrire correctement la ou les lignes dans un fichier de sortie.
Le fichier d'entrée contient, à chaque ligne, un mot. Les mots se classent en cinq différentes catégories. Chaque catégorie est désignée par une lettre :
A - adjectifs
B - adverbes
V - verbes
X - autres catégories
N - les noms
A la fin de chaque mot, il y a un trait d'union. Après le trait d'union, il y a trois possibilités :
1) soit une lettre majuscule (A, B, V ou X)
2) plus d'une lettre majuscule
Exemples :
- AN : le mot est à la fois un adjectif et un nom
- ABN : le mot est à la fois un adjectif, un adverbe et un nom
3) ou rien pour un nom (je n'écris pas le N pour les noms sauf si le mot appartient aussi à une autre catégorie).
Voici un exemple d'un petit fichier d'entrée (entree.txt) :
accrocher-V
aéronef-
agile-A
bien-ABN
ciel-
éducatrice-AN
manger-NV
Le programme devrait générer le fichier de sortie suivant (sortie.txt) :
accrocher-V
aéronef-
agile-A
bien-A
bien-B
bien-
ciel-
éducatrice-A
éducatrice-
manger-
manger-V
Ce n'est pas le cas. Voici le résultat de mon programme :
accrocher-V
-V
aéronef-
agile-A
-A
bien-ABN
-A
ciel-
éducatrice-AN
-A
manger-NV
-
-V
Mon programme est :
# !/usr/bin/perl
use strict;
use warnings;
# Ouverture des fichiers d'entrée et de sortie
open(FICHIER_ENTREE, "entree.txt") or die "Le fichier ne s'ouvre pas: $!";
open(FICHIER_SORTIE, ">sortie.txt") or die "Le fichier ne s'ouvre pas: $!";
# Début du traitement
while(<FICHIER_ENTREE>)
{
if (/^([a-zàâçéèêëîïôùû]+[\*\-\']*[a-zàâçéèêëîïôùû]*[\*\-\']*[a-zàâçéèêëîïôùû]*)(\s*)-(A|ABN|AN|V|NV|\n)$/)
{
my $x = "$_";
print FICHIER_SORTIE "$x";
if ($3=~'A')
{
print FICHIER_SORTIE "-A\n";
}
else
{
if ($3=~'ABN')
{
print FICHIER_SORTIE "-A\n";
print FICHIER_SORTIE "-B\n";
print FICHIER_SORTIE "-\n";
}
else
{
if ($3=~'AN')
{
print FICHIER_SORTIE "-A\n";
print FICHIER_SORTIE "-\n";
}
else
{
if ($3=~'NV')
{
print FICHIER_SORTIE "-\n";
print FICHIER_SORTIE "-V\n";
}
else
{
if ($3=~'V')
{
print FICHIER_SORTIE "-V\n";
}
}
}
}
}
}
} # WHILE
close FICHIER_ENTREE;
close FICHIER_SORTIE;
Le problème concerne la variable $1. Dans le test suivant :
if (/^([a-zàâçéèêëîïôùû]+[\*\-\']*[a-zàâçéèêëîïôùû]*[\*\-\']*[a-zàâçéèêëîïôùû]*)(\s*)-(A|ABN|AN|V|NV|\n)$/)
$1 correspond au mot mais quand je fais d'autres tests comme, par exemple :
if ($3=~'A')
$1 devient A.
Comment garder le mot dans une variable lorsqu'on fait d'autres tests?
Merci
- Comment maintenir le contenu d'une variable?
- Fusionner deux cellules excel en gardant le contenu - Guide
- Word a trouvé du contenu illisible - Guide
- Le fichier à télécharger correspond au contenu brut d’un courrier électronique. de quel pays a été envoyé ce message ? - Guide
- Contenu multimedia messenger disparu - Forum Facebook Messenger
- Vba excel sélectionner une plage de cellules variable ✓ - Forum VB / VBA
2 réponses
Salut,
tu peux, si toutes les lignes contiennent un -, faire un split et mettre ça dans un tableau. Ca évite de gérer avec des regex (mais attention aux noms composés : haut-parleur, par exemple)
@TMP = split(/-/,$LIGNE_LUE);
Ensuite, dans $TMP[0], tu as le nom et dans $TMP[1], tu as les attributs.
Tu peux ensuite splitter les attributs (avec un séparateur vide, donc chaque caractère) et boucler sur le nouveau tableau créé.
Ca peut donner ça (je n'ai pas fait la boucle de lecture) :
#!/usr/bin/perl $mot = "bien-AN"; @TMP = split(/-/,$mot); $mot = $TMP[0]; @attribs = split(//,$TMP[1]); foreach my $attrib (@attribs) { print $mot."-".$attrib."\n"; }
Reste à gérer les exceptions (noms composés...).
Salut blux,
J'ai intégré une boucle de lecture à ton script. Ça ne fonctionne pas tout à fait (mais c'est près). Il y a deux failles :
1) Si la ligne se termine par une (ou des lettres majuscules), le script ajoute le mot avec un trait d'union à la fin du bloc, dans le fichier, ce qui ne doit pas être.
Exemple : Pour la ligne suivante :
bien-ABN
on doit avoir :
bien-A
bien-B
bien-N
et non pas :
bien-A
bien-B
bien-N
bien-
2) Entre les lignes qui contiennent des mots différents, il y a une ligne vide, entre eux, dans le fichier :
Voici mon programme :
Voici mes deux fichiers :
entree.txt
accrocher-V
aéronef-
agile-A
bien-ABN
éducatrice-AN
sortie.txt
accrocher-V
accrocher-
aéronef-
agile-A
agile-
bien-A
bien-B
bien-N
bien-
éducatrice-A
éducatrice-N
éducatrice-
Merci
Non, pour moi, si on rajoute le mot avec un simple tiret, c'est qu'il y a un caractère supplémentaire (invisible) derrière les attributs.
Peux-tu ajouter la ligne suivante après le split de $tmp[1]:
Elle va donner la taille du tableau (le nb d'attributs) et c'est sûrement ici que tu verras qu'il y a un loup (3 au lieu de 2, par exemple).
Dont une explication pourrait être la suivante :
Tu es sous windows ou linux ? Il est possible que la fin de ligne soit considérée comme un caractère et donc traitée en tant qu'attribut.
Tu pourrais dans ce cas, faire un :
avant le split (ou le faire sur $LIGNE_LUE avant son split).
C'est sûrement ce qui fait que tu as une ligne entre chaque mot. En fait, on affiche le mot et son attribut mais comme l'attribut est très vraisemblablement un saut de ligne, ça donne ce résultat de ligne blanche en trop.
Tu peux aussi rajouter le module Data::Dumper en tête de programme avec :
et voir ce que contiennent les différentes variables :
Je pense que mon programme est correct depuis le début ;-))
En simplifiant, ça pourrait donner ça :
Salut,
Je travaille sous Linux Mint.
Mon fichier d'entrée est :
accrocher-V
aéronef-
agile-A
bien-ABN
éducatrice-AN
1) J'ai fait ta ligne de commande "print scalar @attribs;" après le split de $tmp[1]:
Résultat : 21243
Donc, c'est correct : 2 (accrocher-V) // 1 (aéronef-) // 2 (agile-A) ...
2) Ta suggestion d'utiliser la commande chomp m'a rappelé que quelqu'un m'avait déjà conseillé d'utiliser cette commande, il y a longtemps, dans un autre script. J'aurais dû y penser.
J'ai ajouté ton autre ligne "chomp($tmp[1]);" avant le split, mais ça ne fonctionne pas correctement: si la ligne se termine par un trait d'union, le programme ne copie pas la ligne dans le fichier ...
Résultat :
accrocher-V
agile-A
bien-A
bien-B
bien-N
éducatrice-A
éducatrice-N
3) Si j'utilise la ligne de commande "print Dumper @attribs;" ça donne
$VAR1 = 'V';
$VAR1 = 'A';
$VAR1 = 'A';
$VAR2 = 'B';
$VAR3 = 'N';
$VAR1 = 'A';
$VAR2 = 'N';
Donc, pour la ligne "aéronef-", la variable $VAR1 n'a pas de contenu.
4) Ton programme fonctionne correctement si j'ajoute un espacement après le tiret, soit "aéronef- ". C'est ce que je vais faire je crois (ou simplement ajouter la lettre N pour les noms).
5) Dans les mots composés, je vais utiliser l'astérisque au lieu du trait d'union (arc*en*ciel) sinon, ça ne fonctionne pas. C'est simple ensuite de les remplacer, par la suite, par un tiret.
Je ne croyais pas que c’était aussi compliqué.
Merci
Donc, il faut faire un test si scalar @attribs est égal à zéro pour ne pas passer dans la boucle d'affichage des attributs et n'afficher que le nom (en supposant que tu as fait le chomp).
Ca devrait résoudre pas mal de pb...
Et pourquoi ne mets-tu pas l'astérisque comme séparateur entre un mot et ses attributs ?
Dans ce cas, il faudra changer :
par
En Perl, ce qui sert de séparateur à la commande split est une expression régulière et comme l'astérisque a un rôle dans les regex, on la déspécialise avec un backslash (\).
Ligne 45, mettre @attribs au lieu de $attribs, désolé. J'ai écrit sans tester...