Vous êtes sur la page 1sur 9

Centre Informatique pour les Lettres

et les Sciences Humaines


TD 9 : Reconnatre la langue d'un texte





1 - Analyse pralable ............................................................................................................... 2
2 - Cration du projet et dessin de l'interface ........................................................................... 2
3 - La classe de dialogue.......................................................................................................... 3
Le constructeur .............................................................................................................. 3
La fonction f _desi gner Exempl e( ) ................................................................................. 3
La fonction f _aj out er Langue( ) ..................................................................................... 3
La fonction f _exper t i ser ( ) .......................................................................................... 5
4 - La classe CDescr i pt i on..................................................................................................... 6
Le fichier description.h ................................................................................................... 6
La fonction mi seEnRout e( ) ............................................................................................ 8
La fonction anal yse( ) .................................................................................................... 8
La fonction di st ance( ) .................................................................................................. 8


Document du 28/02/06 - Retrouvez la version la plus rcente sur http://www.up.univ-mrs.fr/wcpp
VC++ 6.0 - Qt 3.2 TD 9 : Identifier la langue d'un texte 2/9
Dterminer dans quelle langue un texte est
rdig est une tche dont l'importance s'accrot
avec le nombre de documents lectroniques
accessibles, et qui constitue souvent une tape
pralable des traitements plus ambitieux.

Le programme que nous allons raliser base sa
dcision sur une analyse des frquences
relatives des diffrents caractres composant le
texte. Cette stratgie exige de disposer de points
de comparaison, et notre programme va donc
comporter deux facettes : il doit tre capable
d'une part d'apprendre associer le nom d'une
langue une certaine distribution des
frquences des caractres et, d'autre part, de
dterminer, parmi les langues connues, quelle
est celle dont la distribution des frquences des
caractres est la plus proche de la distribution
observe dans un fichier dont la langue est
inconnue.


L'interface utilisateur du programme ralis au cours du TD 9
1 - Analyse pralable
Outre la gestion de l'interface utilisateur et l'accs aux fichiers de donnes, le programme repose
essentiellement sur l'tablissement de descriptions statistiques des textes utiliss. Cet aspect du
travail sera confi une classe CDescr i pt i on, dont nous allons, comme l'accoutum, dcouvrir
progressivement les caractristiques au cours de la mise au point de la classe de dialogue.
2 - Cration du projet et dessin de l'interface
Crez, en suivant la procdure habituelle, un projet nomm TD09 .

Placez sur le dialogue un QTabWi dget (Menu Tools, catgorie Containers) .

Sur la premire page de ce QTabWi dget , disposez :

- une QTabl e (Menu Tools, catgorie Views) baptise t abl eauLangues

;

- deux QLi neEdi t (Menu Tools, catgorie Input) respectivement nommes nomLangue et
exempl eLangue

;

- deux QPushBut t on (Menu Tools, catgorie Buttons) respectivement nomms b_aj out er et
b_desi gner Exempl e

;

- deux QGr oupBox et deux QLabel explicitant le rle des diffrents widgets (cf. image ci-dessus)
.


Sur la seconde page du QTabWi dget , disposez :

- un QPushBut t on nomm b_exper t i ser ;

- un QText Edi t (Menu Tools, catgorie Input)
nomm ecr an ;

- un QGr oupBox donnant un titre au QText Edi t (cf.
image ci-contre) .


Crez trois slots nomms f _aj out er Langue,
f _desi gner Exempl e et f _exper t i ser , et
connectez-les aux boutons correspondants .

J-L Pris - 28/02/06
VC++ 6.0 - Qt 3.2 TD 9 : Identifier la langue d'un texte 3/9
3 - La classe de dialogue
Notre interface comporte une QTabl e et quelques instructions sont ncessaires pour attribuer des
titres aux colonnes. Cette opration peut tre effectue une fois pour toutes, ds le lancement du
programme. Les instructions correspondantes prennent donc place dans
Le constructeur
TD09Di al ogI mpl : : TD09Di al ogI mpl ( QWi dget * par ent , const char * name, bool modal , 1
WFl ags f ) : TD09Di al og( par ent , name, modal , f )
{ 2
t abl eauLangues- >set NumRows( 0) ; 3
t abl eauLangues- >set NumCol s( 3) ; 4
QHeader * t i t r es = t abl eauLangues- >hor i zont al Header ( ) ; / / on r cupr e l e QHeader 5
t i t r es- >set Label ( 0, " Langue" ) ; / / on l ui i ndi que l es t i t r es des col onnes 6
t i t r es- >set Label ( 1, " Fi chi er de r f r ence" ) ; 7
t i t r es- >set Label ( 2, " Tai l l e" ) ; 8
} 9

Dans le fichier TD09DialogImpl.cpp, ajoutez les lignes 3-8 au constructeur de la classe .
La fonction f _desi gner Exempl e( )
Cette fonction ne peut pas entreprendre quoi que ce soit de significatif, car il n'est pas certain
que, au moment o elle est invoque, le nom de la langue correspondant l'exemple dsign ait
dj t saisi. Elle se contente donc d'afficher le chemin du fichier dsign, ce qui, du mme coup,
rend celui-ci disponible pour la fonction f _aj out er Langue( ) .

voi d TD09Di al ogI mpl : : f _desi gner Exempl e( ) 1
{ 2
exempl eLangue- >set Text ( QFi l eDi al og: : get OpenFi l eName( ) ) ; 3
} 4

Ajoutez la fonction f _desi gner Exempl e( ) votre classe TD09Di al ogI mpl et donnez lui le
contenu suggr ci-dessus .
La fonction f _aj out er Langue( )
Le rle de cette fonction est d'effectuer les calculs ncessaires pour ajouter la "base de
connaissances" du programme la description de la nouvelle langue. Avant de se lancer dans cette
opration, la fonction doit cependant s'assurer que certains cas triviaux sont filtrs. Il faut ainsi
vrifier que l'utilisateur a bien spcifi un nom (5-9) et un fichier d'exemple (10-15) pour la
nouvelle langue :

voi d TD09Di al ogI mpl : : f _aj out er Langue( ) 1
{ 2
QSt r i ng nom= nomLangue- >t ext ( ) ; 3
QSt r i ng chemi n = exempl eLangue- >t ext ( ) ; 4
i f ( nom== " " ) 5
{ 6
QMessageBox: : war ni ng( t hi s, " TD09" , " Donnez un nom cet t e l angue" ) ; 7
r et ur n; 8
} 9
QFi l e l eFi chi er ( chemi n) ; 10
i f ( ! l eFi chi er . exi st s( ) ) 11
{ 12
QMessageBox: : war ni ng( t hi s, " TD09" , " Veui l l ez dsi gner un f i chi er cont enant " 13
" un chant i l l on de " + nom) ;
r et ur n; 14
} 15

Il faut ensuite crer une instance de la classe CDescr i pt i on qui servira stocker les frquences
des diffrents caractres rencontrs dans le fichier d'exemple. Cette instance doit avoir
connaissance du nom de la langue et du fichier d'exemple correspondant :

J-L Pris - 28/02/06
VC++ 6.0 - Qt 3.2 TD 9 : Identifier la langue d'un texte 4/9
CDescr i pt i on aAj out er ; 16
i f ( ! aAj out er . mi seEnRout e( nom, chemi n) ) 17
1
{ 18
QMessageBox: : war ni ng( t hi s, " TD09" , " Le f i chi er " + chemi n + " est i nexpl oi t abl e" ) ; 19
r et ur n; 20
} 21

1 : La classe CDescr i pt i on doit comporter une fonction membre nomme mi seEnRout e( ) dont
les deux paramtres permettent de spcifier respectivement le nom de la langue dcrite et le
chemin d'accs au fichier exemple. Cette fonction renvoie un boolen indiquant si l'instance au
titre de laquelle elle a t excute accepte la mission qui lui est propose.

La "base de connaissances" de notre programme n'est qu'une vulgaire collection d'instances de
CDescr i pt i on. Comme le seul usage que nous allons en faire est de la parcourir pour trouver
l'instance qui "ressemble" le plus la description de notre fichier "mystre", une QVal ueLi st
semble tout fait suffisante.

Ajoutez votre fichier TD09DialogImpl.h une ligne dclarant une variable membre de type QVal ueLi st
<CDescr i pt i on>portant le nom l esLangues .

Avant d'ajouter la description de la nouvelle langue notre collection, il convient de vrifier que
celle-ci ne comporte pas dj une description d'une langue portant le mme nom. Si c'est le cas, il
faut liminer cette ancienne description.

La prsence de deux descriptions diffrentes d'une mme langue n'est pas proprement parler
inconcevable dans le contexte du prsent projet. Il semble toutefois plus clair d'exiger que leur
dsignation reste unique ("Anglais 1" et "Anglais 2", par exemple).

/ / on l i mi ne une vent uel l e ent r e pr cdent e pour cet t e l angue
QVal ueLi st <CDescr i pt i on>: : I t er at or uneLangue = l esLangues. begi n( ) ; 22
whi l e( uneLangue ! = l esLangues. end( ) ) 23
i f ( ( *uneLangue) . nom( ) == nom) 24
uneLangue = l esLangues. r emove( uneLangue) ; 25
2
el se 26
++uneLangue; 27

2 : Une CDescr i pt i on doit tre capable de rvler le nom de la langue qu'elle dcrit.

Il suffit ensuite de demander la nouvelle CDescr i pt i on de procder aux calculs requis (28),
puis de l'ajouter notre collection :

/ / on aj out e l a nouvel l e l angue
QAppl i cat i on: : set Over r i deCur sor ( wai t Cur sor ) ; 28
aAj out er . anal yse( ) ; 29
l esLangues. append( aAj out er ) ; 30
3

L'analyse du fichier d'exemple peut prendre "un certain temps" (nous ne savons rien de sa
taille) et la ligne 27 donne au pointeur de la souris la forme qui indique qu'une opration
longue est en cours (sous Windows, il s'agit par dfaut d'un sablier).

3 : La classe CDescr i pt i on doit comporter une fonction anal yse( ) ordonnant l'instance au
titre de laquelle elle est excute de procder l'analyse du fichier d'exemple (qui doit lui avoir t
pralablement dsign par un appel la fonction mi seEnRout e( ) ).

Pourquoi la fonction mi seEnRout e( ) ne procde-t-elle pas directement l'analyse du fichier
d'exemple ? Parce qu'il s'agit d'une opration potentiellement trs longue, et qu'il est prfrable
que de tels traitements ne soient entrepris que lorsqu'ils sont explicitement demands.

La fonction f _aj out er Langue( ) doit enfin afficher la liste des langues connues, de faon ce que
l'utilisateur sache o il en est. Plutt que d'essayer d'ajouter une ligne t abl eauLangues (ce qui
exigerait des mesures particulires dans le cas o l'une des entres a t supprime), il est
prfrable de vider la QTabl e (30) et d'en reconstituer intgralement le contenu en demandant
aux CDescr i pt i on de fournir elles-mmes les renseignements ncessaires :

J-L Pris - 28/02/06
VC++ 6.0 - Qt 3.2 TD 9 : Identifier la langue d'un texte 5/9
/ / on af f i che l a l i st e des l angues connues
t abl eauLangues- >set NumRows( 0) ; 31
f or ( uneLangue = l esLangues. begi n( ) ; uneLangue! = l esLangues. end( ) ; ++uneLangue) 32
{ 33
i nt l i gne = t abl eauLangues- >numRows( ) ; 34
t abl eauLangues- >set NumRows( l i gne + 1) ; 35
t abl eauLangues- >set Text ( l i gne, 0, ( *uneLangue) . nom( ) ) ; 36
QSt r i ng c = ( *uneLangue) . chemi n( ) ; 37
4
t abl eauLangues- >set Text ( l i gne, 1, c. mi d( c. f i ndRev( " / " ) +1, 100) ) ; 38
t abl eauLangues- >set Text ( l i gne, 2, QSt r i ng: : number ( ( *uneLangue) . t ai l l e( ) ) ) ; 39
} 40
i nt col onne; 41
f or ( col onne = 0 ; col onne < t abl eauLangues- >numCol s( ) ; ++col onne) 42
5
t abl eauLangues- >adj ust Col umn( col onne) ; / / r gl e l a l ar geur des col onnes 43
nomLangue- >set Text ( " " ) ; 44
exempl eLangue- >set Text ( " " ) ; 45
QAppl i cat i on: : r est or eOver r i deCur sor ( ) ; 46
} 47

4 : Une CDescr i pt i on doit pouvoir dire quel fichier elle a analys.

5 : Une CDescr i pt i on doit pouvoir dire combien de caractres elle a analys.

Les lignes 44-45 liminent le risque qu'un utilisateur impatient procde plusieurs ajout de la
mme langue en cliquant plusieurs fois de suite sur le bouton [Ajouter]. La ligne 44 rend la
souris son curseur normal (sous Windows, il s'agit par dfaut d'une flche). L'utilisation de ces
fonctions exige la prsence d'une directive #i ncl ude " qappl i cat i on. h" .

Ajoutez la fonction f _aj out er Langue( ) votre classe TD09Di al ogI mpl et donnez lui le
contenu suggr ci-dessus .
La fonction f _exper t i ser ( )
Cette fonction doit, elle aussi, commencer par filtrer les cas dans lesquels elle ne peut rien
accomplir d'utile :

voi d TD09Di al ogI mpl : : f _exper t i ser ( ) 1
{ 2
i f ( l esLangues. i sEmpt y( ) ) 3
{ 4
QMessageBox: : war ni ng( t hi s, " TD09" , " J e ne connai s aucune l angue ! " ) ; 5
r et ur n; 6
} 7
QSt r i ng chemi n = QFi l eDi al og: : get OpenFi l eName( ) ; 8
QFi l e l eFi chi er ( chemi n) ; 9
i f ( ! l eFi chi er . exi st s( ) ) 10
{ 11
QMessageBox: : war ni ng( t hi s, " TD09" , " Veui l l ez dsi gner un f i chi er cont enant un t ext e" ) ; 12
r et ur n; 13
} 14
CDescr i pt i on aI dent i f i er ; 15
i f ( ! aI dent i f i er . mi seEnRout e( " I nconnue" , chemi n) ) 16
{ 17
QMessageBox: : war ni ng( t hi s, " TD09" , " Echec d' anal yse de " + chemi n) ; 18
r et ur n; 19
} 20

Une fois ces prcautions prises, l'expertise proprement dite peut commencer. Il s'agit de parcourir
notre collection de descriptions en cherchant celle qui se rapproche le plus du texte expertiser :
la langue (connue) de cette description est la rponse la plus vraisemblable que le programme
puisse fournir la question pose.

Le calcul de la distance entre les descriptions de deux textes sera assur par une fonction
membre de CDescr i pt i on, mais notre programme va comporter un petit raffinement
supplmentaire : il va analyser progressivement le texte mystrieux, et nous dire quel moment il
J-L Pris - 28/02/06
VC++ 6.0 - Qt 3.2 TD 9 : Identifier la langue d'un texte 6/9
a atteint sa conclusion finale quant la langue de celui-ci. Ce raffinement impose de nouvelles
contraintes la classe CDescr i pt i on :

6 : La classe CDescr i pt i on doit comporter une fonction est Fi ni ( ) renvoyant un boolen qui
indique si l'analyse est parvenue la fin du texte.

7 : La fonction CDescr i pt i on: : anal yse( ) doit accepter un paramtre lui indiquant combien de
caractres elle doit traiter.

Sans oublier que

8 : La classe CDescr i pt i on doit comporter une fonction di st ance( ) renvoyant une mesure de
l'cart entre les statistiques contenues dans l'instance au titre de laquelle elle est invoque et
celles contenues dans l'instance qui lui est passe comme paramtre.

QAppl i cat i on: : set Over r i deCur sor ( wai t Cur sor ) ; 21
QSt r i ng ver di ct = " Er r eur " ; 22
unsi gned l ong changement Avi s; 23
doubl e di st anceMi ni = DBL_MAX; 24
whi l e ( ! aI dent i f i er . est Fi ni ( ) ) 25
{ 26
aI dent i f i er . anal yse( 100) ; / / l i t une " t r anche" du t ext e myst r i eux 27
7
6
/ / cher che l a l angue qui r essembl e l e pl us aux st at i st i ques act uel l es 28
QVal ueLi st <CDescr i pt i on>: : I t er at or uneLangue; 29
f or ( uneLangue=l esLangues. begi n( ) ; uneLangue ! = l esLangues. end( ) ; ++uneLangue) 30
{ 31
doubl e di st ance = aI dent i f i er . di st ance( *uneLangue) ; 32
8
i f ( di st ance < di st anceMi ni ) 33
{/ / uneLangue vi ent de bat t r e l e r ecor d de pr oxi mi t 34
di st anceMi ni = di st ance; 35
i f ( ( *uneLangue) . nom( ) ! = ver di ct ) 36
changement Avi s = aI dent i f i er . t ai l l e( ) ; / / l e ver di ct va changer 37
ver di ct = ( *uneLangue) . nom( ) ; 38
} 39
} 40
} 41
QSt r i ng message = " \ nMon avi s: %1\ nDci si on st abi l i se apr s anal yse de %2 car act r es\ n" ; 42
ecr an- >set Text ( ecr an- >t ext ( ) + chemi n + 43
message. ar g( ver di ct ) . ar g( QSt r i ng: : number ( changement Avi s) ) ) ;
QAppl i cat i on: : r est or eOver r i deCur sor ( ) ; 44
} 45

Remarquez, ligne 24, l'utilisation d'une constante (dfinie dans le fichier float.h) permettant de
donner di st anceMi ni une valeur draisonnablement grande qui garantit que la premire
distance calcule va tre considre comme un record de proximit.

Ajoutez la fonction f _exper t i ser ( ) votre classe TD09Di al ogI mpl et donnez lui le contenu
suggr ci-dessus (sans oublier les #i ncl ude ncessaires) .
4 - La classe CDescr i pt i on
Ajoutez une classe CDescr i pt i on votre projet .
Le fichier description.h
La mise au point de la classe de dialogue nous a conduit faire huit "promesses" concernant cette
classe, et l'interface (ie. la section publ i c: ) de CDescr i pt i on s'en trouve quasiment dicte :

cl ass CDescr i pt i on 1
{ 2
publ i c: 3
CDescr i pt i on( ) ; 4
vi r t ual ~CDescr i pt i on( ) ; 5

J-L Pris - 28/02/06
VC++ 6.0 - Qt 3.2 TD 9 : Identifier la langue d'un texte 7/9
Les lignes 4 et 5 ont t gnres par Visual C++ lorsque vous avez cr la classe. Elles dclarent
un constructeur et le destructeur de la classe (cf. Leon 10). Si elles vous gnent, vous pouvez
les effacer, mais il vous faudra alors effacer aussi les dfinitions (vides) des fonctions
correspondantes que Visual C++ a places dans le fichier description.cpp.

bool mi seEnRout e( QSt r i ng nomFi ch, QSt r i ng chemi nFi ch) ; / / poi nt 1 6
QSt r i ng nom( ) const {r et ur n m_nom; } / / poi nt 2 7

Comme doivent le faire toutes les fonctions qui ne font que communiquer l'appelant une
information concernant l'tat de l'instance au titre de laquelle elles sont appeles (sans modifier
cet tat), la fonction nom( ) affiche clairement cette caractristique en se dclarant constante.

Ces fonctions sont gnralement trs brves, et peuvent donc tre dfinies en mme temps que
la classe. Dans le cas prsent, il est clair que nom( ) a besoin que mi seEnRout e( ) ait stock le
nom de la langue dans une variable membre.

voi d anal yse( unsi gned l ong l ongueur = ULONG_MAX) ; / / poi nt s 3 et 7 8

L'utilisation d'un paramtre de type "entier long positif" permet de placer la valeur maximale
admissible aussi haut qu'il est possible de le faire sans complications excessives (et bien inutiles
dans ce cas). Comme dans le de la variable di st anceMi ni rencontre plus haut, une constante
prdfinie permet de donner ce paramtre une valeur par dfaut maximale, qui garantit
l'analyse de l'intgralit du fichier si l'appelant n'a spcifi aucune l ongueur . La mme fonction
tient donc la fois les promesses 3 et 7.

QSt r i ng chemi n( ) const {r et ur n m_chemi n; } / / poi nt 4 9
unsi gned l ong t ai l l e( ) const {r et ur n m_nbCar Anal yses; } / / poi nt 5 10

Deux nouvelles variables membres s'imposent donc. La t ai l l e( ) dont il s'agit ici n'est pas celle
du fichier, mais bien le nombre de caractres utiliss pour tablir les statistiques actuelles.

bool est Fi ni ( ) const {r et ur n m_t ext eAAnal yser . i sEmpt y( ) ; } / / poi nt 6 11

Derrire cette ligne se cache une dcision fondamentale : nous allons placer le contenu du fichier
dans une variable membre (une QSt r i ng). Aprs chaque analyse partielle, nous retirerons du
t ext eAAnal yser les caractres nouvellement pris en compte dans les statistiques. L'analyse
sera donc bien termine lorsque la QSt r i ng en question sera vide.

doubl e di st ance ( const CDescr i pt i on & unAut r e) const ; / / poi nt 8 12

Les CDescr i pt i on sont des objets volumineux (elles contiennent une frquence pour chacun des
caractres apparaissant dans le texte analys et une copie du texte non encore analys). Il faut
donc viter de transmettre une valeur de ce type une fonction, ce qui l'obligerait crer une
instance locale pour y copier toutes ces donnes. L'utilisation d'une rfrence un objet
constant vite cette copie sans pour autant permettre la fonction de modifier un objet qui ne
lui appartient pas.

La partie pr ot ect ed: de CDescr i pt i on comporte videmment la dclaration des variables
membre dont nous venons de dcouvrir la ncessit :

pr ot ect ed: 13
QSt r i ng m_nom; 14
QSt r i ng m_chemi n; 15
doubl e m_nbCar Anal yses; 16
QSt r i ng m_t ext eAAnal yser ; 17

Il faut aussi prvoir le stockage des statistiques. Etant donn qu'il s'agit de mmoriser un nombre
d'occurrences pour chaque caractre, une QMap semble tout fait adapte :

QMap <QChar , unsi gned l ong> m_f r equence; 18
}; 19

Les cls de cette QMap ne sont pas des char , mais des QChar . Outre la simplification que ceci
promet (les QSt r i ng sont composes de QChar , et non de char ), il serait dommage de se priver
de l'indpendance que les classes Qt nous offrent vis vis du type de codage utilis dans les
fichiers (ASCII, Unicode sur 8 ou 16 bits). Grce cette indpendance, notre programme va en
effet tre capable de reconnatre la langue utilise dans un fichier, mme lorsque le seul exemple
de cette langue qui lui a pralablement t montr utilisait un codage diffrent.
J-L Pris - 28/02/06
VC++ 6.0 - Qt 3.2 TD 9 : Identifier la langue d'un texte 8/9
La fonction mi seEnRout e( )
Cette fonction assure la "pseudo-initialisation" des variables membre (3-6) et assure la lecture du
fichier (7-11) :

bool CDescr i pt i on: : mi seEnRout e( QSt r i ng n, QSt r i ng chemi n) 1
{ 2
m_nom= n; 3
m_chemi n = chemi n; 4
m_f r equence. cl ear ( ) ; 5
m_nbCar Anal yses = 0; 6
QFi l e dat a( m_chemi n) ; 7
i f ( ! dat a. open( I O_ReadOnl y | I O_Tr ansl at e) ) 8
r et ur n f al se; 9
QText St r eaml eFi chi er ( &dat a) ; 10
m_t ext eAAnal yser = l eFi chi er . r ead( ) ; 11
r et ur n t r ue; 12
} 13

La lecture (11) de l'intgralit du fichier dans une QSt r i ng n'est pas gnralement
recommandable, car elle suppose implicitement que le fichier n'est pas dmesurment grand.
Dans le cas prsent, les fichiers "naturels" ne poseront aucun problme (mme un roman trs
long ne fera jamais plus de quelques millions de caractres). Il pourrait en aller autrement, bien
sr, en cas de cration d'un fichier spcialement destin faire des statistiques, o seraient
concatns des milliers de textes d'origines diverses.

Ajoutez cette dfinition de la fonction mi seEnRout e( ) votre fichier description.cpp .
La fonction anal yse( )

voi d CDescr i pt i on: : anal yse( unsi gned l ong nbCar AAj out er ) 1
{ 2
i nt posi t i on = 0; 3
whi l e ( posi t i on < nbCar AAj out er && posi t i on < m_t ext eAAnal yser . l engt h( ) ) 4
{ 5
QChar aCompt abi l i ser = m_t ext eAAnal yser [ posi t i on] ; 6
++m_f r equence[ aCompt abi l i ser ] ; 7
++posi t i on; 8
} 9
m_nbCar Anal yses += posi t i on; 10
m_t ext eAAnal yser . r emove( 0, posi t i on) ; 11
} 12

Attention, aux lignes 10 et 11, c'est bien la variable posi t i on qu'il faut utiliser, et non
nbCar AAj out er . En effet, cette dernire ne contient le nombre de caractres effectivement traits
que si le t ext eAAnal yser tait encore assez long pour satisfaire compltement la demande
d'analyse.

Ajoutez cette dfinition de la fonction anal yse( ) votre fichier description.cpp .
La fonction di st ance( )
La distance entre deux sries ordonnes de nombres peut tre calcule en faisant la somme des
carrs des carts. Ainsi, la distance entre 2, 3, 1 et 1, 5, 1 sera (2-1)
2
+ (3-5)
2
+ (1-1)
2
= 1 + 4 + 0,
soit 5.

Dans le cas des CDescr i pt i on, l'application de ce principe doit tenir compte de deux
particularits prvisibles : les deux textes analyss ne sont sans doute pas de la mme longueur,
et certains caractres n'apparaissent peut-tre que dans l'un des deux textes.

La question de la longueur des textes est facilement rsolue en considrant les frquences
relatives des caractres plutt que leurs frquences absolues.

La question des "caractres manquants" impose de parcourir les deux collections de frquences.
Etant donn que ces deux collections sont "read only" (celle de l'instance au titre de laquelle la
fonction est excute ne peut tre modifie parce que la fonction est dclare constante, et celle de
J-L Pris - 28/02/06
VC++ 6.0 - Qt 3.2 TD 9 : Identifier la langue d'un texte 9/9
l'autre instance ne peut tre modifie car la fonction y accde via une "rfrence un objet
constant"), leur parcours exige un "itrateur sur objet constant" :

doubl e CDescr i pt i on: : di st ance( const CDescr i pt i on & aut r e) const 1
{ 2
doubl e di st anceCal cul ee = 0; 3
QMap<QChar , unsi gned l ong>: : Const I t er at or i t ; 4
/ / on commence par l es car act r es qui appar ai ssent chez nous
f or ( i t = m_f r equence. begi n( ) ; i t ! = m_f r equence. end( ) ; ++i t ) 5
{ 6
doubl e ecar t = i t . dat a( ) / doubl e( t ai l l e( ) ) ; 7
i f ( aut r e. m_f r equence. cont ai ns( i t . key( ) ) ) / / i l appar ai t aussi chez l ' aut r e 8
ecar t - = aut r e. m_f r equence [ i t . key( ) ] / doubl e( aut r e. t ai l l e( ) ) ; 9
di st anceCal cul ee += ecar t * ecar t ; / / on f ai t l a somme des car r s des car t s 10
} 11

Si un caractre n'apparat pas dans l'autre texte, sa frquence y est nulle et l'cart est donc gal
sa frquence (relative) dans le premier texte (7). Si le caractre apparat dans les deux textes,
il faut en revanche calculer (9) la diffrence entre ses deux frquences (relatives).

/ / i l ne f aut pas oubl i er ceux qui appar ai ssent chez l ' aut r e mai s pas chez nous
f or ( i t = aut r e. m_f r equence. begi n( ) ; i t ! = aut r e. m_f r equence. end( ) ; ++i t ) 12
{ 13
doubl e ecar t = i t . dat a( ) / doubl e( aut r e. t ai l l e( ) ) ; 14
i f ( ! m_f r equence. cont ai ns( i t . key( ) ) ) 15
di st anceCal cul ee += ecar t * ecar t ; 16
} 17
r et ur n di st anceCal cul ee; 18
} 19

Lors du parcours des frquences observes dans l'autre texte, seuls nous intressent les
caractres qui n'apparaissent pas dans le premier (15). Par dfinition, l'cart correspondant est
donc gal la frquence (relative) du caractre dans le second texte (14).

Ajoutez cette dfinition de la fonction di st ance( ) votre fichier description.cpp .

Vous pouvez maintenant compiler le programme et, si vous n'avez oubli aucune des
(nombreuses) directives #i ncl ude ncessaires, procder quelques tests.

Vous pouvez trouver ici ou l des textes rdigs dans diverses langues.
J-L Pris - 28/02/06