M1202 - TP Bonus
Durée : 3h00
Objectifs
- Récupérer les paramètres d'un programme Java.
- Traiter des fichiers textes.
- Utiliser les fonctions sur les chaînes de caractères.
- Définir des fonctions de base sur les tableaux.
Au menu
- Consignes
- Paramètres d'un programme Java
- Chargement et affichage d'un fichier texte
- Remplacement des caractères spéciaux d'un texte
- Extraction des mots d'un texte
- Alignement de deux textes
Lisez attentivement cet énoncé de TP/TD
en suivant les instructions.
En cas d'interrogation,
faites appel à moi,
que ce soit pour en savoir plus sur un des points abordés pendant le TP, ou
pour savoir comment effectuer une des tâches demandées (numérotées pour pouvoir
y faire référence simplement).
Surtout
ne restez pas bloqué(e) sur une des questions.
Entre parenthèses, à côté des titres de sous-sections, est indiqué
le temps que vous avez dû passer à effectuer les étapes précédentes.
Au cours de ce TP, nous allons traiter des fichiers textes
stockés sur le disque dur, dont l'adresse est fournie
en paramètre du programme.
Votre objectif minimal doit être d'arriver jusqu'à la fin de la section D.
Lors de l'appel d'un programme en Java, par la commande
java nom_du_programme,
il est possible de faire suivre le nom du programme par des paramètres séparés
par des espaces. Par exemple, si on veut indiquer deux paramètres
param1
et
param2 pour le programme
TD5, on exécutera dans le terminal la commande suivante :
java TD5 param1 param2
Ces paramètres sont alors stockés dans un tableau de chaînes de caractères,
appelé
arg, qui est donné comme paramètre d'entrée de la fonction
main.
Ceci explique que la déclaration de la fonction main d'un programme Java
est toujours de la forme
public static void main(String[] arg) dans les exemples que nous avons
vus jusqu'à présent.
Nous allons tout d'abord voir comment compter et récupérer ces paramètres.
Pour cela, commencez par
question(); ?>créer un
dossier dédié à ce TP5 (de la même manière qu'aux TP précédents), puis
question(); ?>enregistrez-y ce fichier
TP5.java, ainsi que TP5Apollinaire.txt
et TP5Hugo.txt.
Maintenant,
question(); ?>ajoutez dans le main
une instruction qui permet d'afficher
le nombre de paramètres. Testez-la en compilant
TD5.java, puis en exécutant TD5 avec un, deux, ou aucun paramètre.
En utilisant un test avant l'affichage dans le main,
question(); ?>faites afficher un message du type
"x parametre en entree du programme.", où
x correspond au nombre
de paramètres en entrée du programme, et le mot "parametre" est bien accordé,
c'est-à-dire qu'il est au pluriel si
x est strictement supérieur à 1.
Vous devez donc obtenir un résultat similaire à celui de la copie d'écran
ci-contre.
question(); ?>Faites ensuite un parcours du tableau
arg pour afficher tous les paramètres en entrée du programme, précédés
de
Parametre x :, où
x est le numéro du paramètre (le premier
paramètre a pour numéro 0). Vous devez obtenir un résultat similaire
à celui de la copie d'écran ci-contre.
Une fonction permettant de récupérer le contenu d'un fichier texte du disque
dur a déjà été programmée dans le fichier
TP5.java. Elle s'appelle
ouvreFichier et fonctionne de la façon suivante :
- elle
prend en entrée une chaîne de caractères qui contient une adresse
de fichier texte. Cette adresse peut être soit une adresse relative (par rapport
à l'emplacement dans lequel on se trouve au moment de l'exécution du programme,
par exemple TP5Hugo.txt),
soit une adresse absolue (par exemple, M:\INF120\TP5\TP5Hugo.txt ; voir le TP1 pour la définition des termes "adresse
absolue" et "adresse relative").
- elle renvoie en sortie un tableau de chaînes de caractères, dont
chaque case contient une ligne du fichier texte dont l'adresse est
donnée en entrée.
question(); ?>Ajoutez dans la fonction
main le code permettant de stocker, dans un tableau
de chaînes de caractères appelé texte, les lignes d'un fichier
texte dont l'adresse est donnée comme premier paramètre du
programme Java.
Indication à surligner si vous bloquez :
dans la fonction main,
récupérez dans une variable adresse le premier paramètre
en entrée du programme Java,
puis appelez la fonction ouvreFichier sur cette variable
adresse, et stockez le résultat renvoyé par cette fonction
dans un tableau de chaînes de caractères appelé texte.
Puis parcourez ce tableau texte pour afficher le contenu
de chacune de ses cases, l'une après l'autre.
question(); ?>Avant l'affichage de chaque ligne,
affichez le numéro de ligne
A cause des numéros 1, 2, 3, etc., qui sont plus courts que 10, 11, 12, etc.,
qui sont eux-mêmes plus courts que 101, 102, 103, etc., certaines lignes sont
un peu décalées.
question(); ?>Utilisez
un test pour ajouter suffisamment de zéros avant le numéro de ligne,
pour que chaque numéro de ligne ait exactement trois chiffres
(il y aura donc le même alignement pour toutes les lignes de 1 à 999).
Vous devez obtenir un résultat similaire à celui de la copie d'écran ci-contre.
Les lettres accentuées s'affichent mal dans le terminal. On va donc
écrire une fonction
remplaceCaracteres qui prend en
entrée une chaîne de caractères, et renvoie cette chaîne où
les lettres "é", "è" et "ê" ont été remplacées par "e",
la lettre "à" a été remplacée par "a", etc.
Remarque sur la fonction caractere :
Vous pouvez aller voir le code de la fonction caractere, dans le fichier
TP5.java, pour découvrir comment on peut traiter les chaînes de caractères
en Java. L'instruction return chaineCar.substring(i-1,i); est utilisée,
ce qui signifie que la fonction renvoie la sous-chaîne de la
chaîne de caractères chaineCar fournie en entrée, allant du caractère
numéroté i-1 au caractère numéroté i. Remarquez que les
caractères d'une chaîne de caractères en Java sont numérotés à partir
de zéro (ce qui explique le "i-1"). Remarquez aussi que contrairement
à l'habitude où les paramètres d'une fonction sont tous mis entre
parenthèses lors de l'appel de la fonction, ici, le paramètre chaineCar
est mis avant le nom de la fonction, séparé d'un point. Ceci vient
du fait que Java est un langage objet (ce que vous verrez en détails
au module INF250) et s'interprète de la manière suivante : on peut
appliquer toute une liste d'actions sur l'objet chaineCar qui est
une chaîne de caractères, notamment : récupérer ce qui se trouve
entre deux positions de la chaîne de caractères avec substring.
question(); ?>Écrivez
cette fonction remplaceCaracteres,
puis utilisez-la pour afficher une version du poème sans
caractères spéciaux. Pour cela, vous pouvez (devez ?) utiliser
la fonction
caractere qui prend en entrée
une chaîne de caractères
chaineCar et un entier
i,
et renvoie le
i-ième caractère ; ainsi que la fonction
chainesEgales qui prend en entrée deux chaînes de caractères,
et renvoie
true si elles sont égales,
false sinon.
Indication à surligner si vous bloquez :
Vous allez recréer une nouvelle chaîne
de caractères à partir de la chaîne chaineCar, en
partant d'une nouvelle chaîne vide :
pour chaque caractère de chaineCar, soit vous l'ajoutez
à la nouvelle chaîne, s'il n'a pas d'accent ; soit vous ajoutez
sa version sans accent à la nouvelle chaîne, s'il a un accent.
Le problème de la fonction
remplaceCaracteres précédente est
qu'elle nécessite de définir les lettres à remplacer à l'intérieur
du code de la fonction. Ainsi, si vous voulez choisir d'autres
caractères à remplacer (par exemple pour la gestion des caractères
spéciaux espagnols ou allemands), il faudra modifier cette fonction.
Une solution préférable est de fournir en entrée de la fonction
un tableau
caracteres de chaînes de caractères, dont chaque case contient
un caractère spécial à remplacer (par exemple le tableau
{"é","è","ê","à","ù"}), ainsi qu'un deuxième tableau
remplacants qui contient dans chaque case le caractère à
utiliser pour le remplacement (par exemple le tableau
{"e","e","e","a","u"}). Un avantage du langage Java est que,
pour cela, vous pouvez garder le même nom de fonction,
remplaceCaracteres,
car les entrées sont différentes de l'autre fonction
remplaceCaracteres
définie plus haut.
question(); ?>Écrivez cette nouvelle
fonction remplaceCaracteres. Vous pouvez bien sûr commencer
par un copier-coller de la précédente fonction
remplaceCaracteres.
question(); ?>Créez deux tableaux de chaînes de caractères
caracteres et remplacants dans la fonction main,
et utilisez-les dans l'appel de la fonction remplaceCaracteres.
Remarque : pour créer un tableau
tab déjà déclaré, en utilisant l'"écriture compressée",
il ne suffit pas d'écrire, par exemple,
tab = {"*","*","*"}, mais
il faut repréciser le type du tableau, avec une instruction du type
tab = new String[]{"*","*","*"}.
question(); ?>Remplacez toutes les cases du tableau remplacants
par la chaîne de caractères "*" pour voir si cela remplace effectivement toutes
les lettres accentuées par des étoiles.
question(); ?>Appelez, depuis la fonction main,
la fonction remplaceCaracteres avec deux tableaux
en entrée, pour remplacer tous les signes de ponctuation par des espaces.
Cette partie du TP sera poursuivie au prochain TP...
question(); ?>Écrivez une fonction
dansTableau qui prend en entrée une chaîne de caractères
mot
et un tableau de chaînes de caractères
dico et renvoie
true si
mot apparaît dans une case de
dico, et
false sinon.
question(); ?>Écrivez une fonction
ajouteFinTableau qui prend en entrée une chaîne de caractères
mot
et un tableau de chaînes de caractères
dico, et renvoie
le tableau
dico à la fin duquel le mot
mot a été ajouté.
Attention, comme il est impossible de changer la taille d'un tableau,
il va falloir recopier le tableau
dico dans un tableau plus grand
d'une case, et ajouter
mot dans la dernière case de ce nouveau tableau.
question(); ?>Écrivez une fonction
insereDansTableau, qui utilise les deux fonctions précédentes,
et prend en entrée une chaîne de caractères
mot
et un tableau de chaînes de caractères
dico, et renvoie
le tableau
dico dans lequel le mot
mot a été ajouté
s'il n'y était pas déjà.
question(); ?>Écrivez une fonction
creeDico, qui prend en entrée deux tableaux de chaînes de caractères,
un nommé
texte, qui correspond à un texte (une ligne du texte par
case du tableau), et l'autre nommé
dico qui correspond à une
liste de mots, et ajoute dans
dico tous les mots de
texte
(sauf s'ils sont déjà dans
dico).
question(); ?>Utilisez la fonction
creeDico depuis la fonction main,
pour afficher la liste des mots du texte fourni en paramètre
du programme Java.
question(); ?>Essayez-la
sur les deux textes TP5Hugo.txt et
TP5Apollinaire.txt, et sur un autre texte de votre choix.
Nous allons voir dans cette section comment aligner le mieux possibles deux versions d'un même texte avec de légères différences.
Étant donné deux tableaux de chaînes de caractères
t1 et
t2, alignez le tableau
t2 avec
t1, c'est-à-dire
question(); ?>créez une fonction aligneTableaux qui crée un nouveau tableau PositionDansT1 donnant pour chaque mot de t2 la position dans t1 du mot identique correspondant. Si aucun mot ne correspond, indiquez l'entier -1. Vous commencerez par proposer un algorithme glouton, c'est-à-dire un algorithme qui va, successivement pour chaque mot de
t1, chercher parmi les
k prochains mots de
t2 pas encore associés à
t1 (prendre par exemple
k=10).
Testez votre algorithme sur les deux textes suivants avec
k=20 :
Cet algorithme "glouton" pose plusieurs problèmes :
- si plus de dix cases sont insérés à la suite les uns des autres dans le deuxième tableau par rapport au premier, on ne pourra pas détecter l'alignement entre le premier tableau et le second en prenant une valeur de k inférieure ou égale à 10
- le principe de l'algorithme "glouton" est qu'il considère que le premier mot trouvé dans le second texte qui correspond à un mot du premier est en relation avec lui. Ceci pourrait conduire à faire des alignements non optimaux, c'est-à-dire moins longs qu'on ne pourrait en étant plus patient pour associer le mot du premier texte avec une autre occurrence du mot dans le second. Par exemple si le premier texte est "a b a a a a" et que le second est "a b c a b a a a a", l'algorithme glouton renvoie le tableau {0 1 5 6 7 8} alors que le second renvoie {3 4 5 6 7 8} qui correspond à une chaîne de caractères commune contigüe de 6 caractères.
question(); ?>Comprenez et codez en Java l'algorithme de Needleman Wunsch pour aligner les deux tableaux. En cas de difficultés à comprendre l'algorithme, la
page Wikipedia anglaise est davantage illustrée.