Compter nombre d'occurence

Signaler
Messages postés
6
Date d'inscription
samedi 29 janvier 2005
Statut
Membre
Dernière intervention
12 février 2005
-
Messages postés
1023
Date d'inscription
dimanche 1 août 2004
Statut
Membre
Dernière intervention
17 août 2008
-
Bonjour,



Je suis tout nouveau et surtout tout débutant sous delphi.

J'ai une question qui me tracasse et que je ne trouve pas sur le net :



Imaginons que l'on tape une chaîne de caractères dans un Edit.

J'aimerais pouvoir écrire une fonction qui renvoie
le nombre d'occurences de la lettre la plus présente dans cet Edit,
sans distinction majuscule/minuscule.

Pour cela je cliques sur le bouton OK, qui va m'écrire dans un label le nombre d'occurence.

Et à la limite en ignorant les accents, mais ceci est un extra.



Je sais que cela peut paraître complexe mais je suis très intérréssé par cela.

Merci d'@vance !

8 réponses

Messages postés
1418
Date d'inscription
samedi 12 juin 2004
Statut
Membre
Dernière intervention
5 juillet 2010
10
Tu peux faire comme ceci :
procedure
TForm1.Button1Click(Sender: TObject);
var
      str : string;
      count, nbtotal : integer;
begin
      nbtotal :=  0; // On initialise le nombre de lettres
      str := LowerCase(Edit1.Text); // On met toute la chaîne en minuscules
       for  count : = 1to Length(str) do // On parcours toute la chaîne...
        if str[count] =  'e'  then  inc(nbtotal); // Ici, on cherche les "e"
      Label1.Caption : = IntToStr(nbtotal); // Puis, on affiche le nombre de "e" trouvés
end;



@+
Bonne Prog'
Nico



<HR>
N'oubliez pas de cliquer sur Réponse acceptée lorsque la réponse vous convient !
Messages postés
1418
Date d'inscription
samedi 12 juin 2004
Statut
Membre
Dernière intervention
5 juillet 2010
10
Je complète mon code...
Pour une meilleure compatibilité, tu peux remplacer "LowerCase" par "AnsiLowerCase".
Pour les accents, comme l'a utilisé GrandVizir dans sa source "Des Chiffres Et Des Lettres", tu peux utiliser une table de conversion pour les supprimer lors du test... Merci à lui pour cette idée !


 TAccentTbl =   record 
    _From : string;
    _Dest : char;
 end;

var
str : string;


const MaxAccentTable  = 7;
      AccentTable : array[0..MaxAccentTable] of TAccentTbl = 
         ( (_From : 'àäâã'  ;  _Dest : 'a' ),
           (_From : 'ç'     ;  _Dest : 'c' ),
           (_From : 'éèêë'  ;  _Dest : 'e' ),
           (_From : 'ìïî'   ;  _Dest : 'i' ),
           (_From : 'ñ'     ;  _Dest : 'n' ),
           (_From : 'ôöò'   ;  _Dest : 'o' ),
           (_From : 'ûüù'   ;  _Dest : 'u' ),
           (_From : 'ÿ'     ;  _Dest : 'y' )
         );


 IMPLEMENTATION 


function NoAccents(S:string):string;
  //ENLEVE LES ACCENTS D'UNE CHAÎNE EN MINUSCULES
var x, i : integer;
begin
   S: =AnsiLowerCase(S);
   //L'idée est le parcours de la table de conversion
  for x:= 1  to  Length(S) do
     for i: =0 to MaxAccentTable do
       if Pos(S[x],AccentTable[i]._From)<>0 then
         S[x]:= AccentTable[i]._Dest; //si accentué, alors on remplace par le caractère non accentué
   str:=S;
  end ;


procedure
 TForm1.Button1Click(Sender: TObject);
var count, nbtotal : integer;
begin
      nbtotal : = 0;
      str :=  AnsiLowerCase(Edit1.Text); // On convertit la chaîne en minuscules
      NoAccents(str); // Enlève les accents avec la méthode de GrandVizir
       for  count : = 1 to Length(str) do
           if str[count] =  'e'  then  inc(nbtotal); // On teste la présence du "e"
      Label1.Caption : = IntToStr(nbtotal); // On affiche le nombre d'occurences trouvées
end


Voilà... J'espère que cela te conviendra !

@+
Bonne Prog'
Nico

N'oubliez pas de cliquer sur Réponse acceptée lorsque la réponse vous convient !
Messages postés
240
Date d'inscription
dimanche 31 octobre 2004
Statut
Membre
Dernière intervention
31 décembre 2006
1
Je suis d'accord avec toi ni69, cependant il recherche la lettre qui
revient le plus souvent dans un pot et donc pas forcement le 'e'.

Donc architect à toi de modifier cette source.



Soit tu fais le même principe en répétant cette source pour
toutes les lettres de l'alphabet : tu créer un tableau à 2 dimensions
avec toutes les les lettres de l'alphabet et le nombre d'occurence et
au lieu de mettre if str[count] = 'e' tu mets
if str[count] = alphabet[i] avec une boucle for i:=1 to 26 tu aura ton résultat en cherchent le max dans le tableau



Ou alors au lieu de créer le tableau de tout l'alphabet, tu le fais à
partir des lettres du Tedit ( je t'envoie dans l'aide de delphi pour
voir la fonction copy sur une chane de caractère ) et idem ta réponse
se fera par la recherche du max dans ton tableau


N'oubliez pas de cliquer sur réponse acceptée si la réponse vous convient !!!
Messages postés
1418
Date d'inscription
samedi 12 juin 2004
Statut
Membre
Dernière intervention
5 juillet 2010
10
Effectivement sim51, j'avais oublié ce détail...


@+
Bonne Prog'
Nico



<HR>
N'oubliez pas de cliquer sur Réponse acceptée lorsque la réponse vous convient !
Messages postés
1023
Date d'inscription
dimanche 1 août 2004
Statut
Membre
Dernière intervention
17 août 2008
1
Hi,



Je raisonnerais plutot comme sim51 à une petite différence près: je
cree un Counts: array [Char] of Integer initialisé à 0, le mets la
chaine en minuscules (ou en maj), puis je parcours la chaine caractere
par caractere.



Comme cela j'incrémente Counts[S[c]] à chaque caractère parcouru (c, comme var de controle, S étant la chaine)



Après on cherche le plus gros nombre en parcourant le tableau et on renvoie le résultat.



Ce qui donne

procedure OccurenceLettrePlusPresente(S: string; var Lettre: Char; var Nbre: Integer);

var

  i: Integer;

  C, Max: Char;

  Occurences: array [Char] of Integer;

begin

  FillChar(Occurences,SizeOf(Occurences),0);   // On initialise tout à zéro

  S:=AnsiUpperCase(S); // Pour ignorer la casse.



  for i:=1 to Length(S) do

  begin

    Inc(Occurences[S[i]]); // On incrémente.

  end;



  Max:=#0;

  for C:=Low(Char) to High(Char) do

    if Occurences[C] > Occurences[Max] then

      Max:=C;



  Lettre:=Max;

  Nbre:=Occurences[Max];

end;



Et l'on utilise la procedure comme cela: (dans l'évenement OnClick d'un Bouton)

procedure TForm1.Button1Click(Sender: TObject);

var

  Lettre: Char;

  Nbre: Integer;

begin

{ Le texte est place dans l'Edit1 et le résultat s'affichera dans le Label1 }

  OccurenceLettrePlusPresente(Edit1.Text,Lettre,Nbre);

  Label1.Caption:=Format('La lettre la plus présente est le "%s" avec %d itérations',[Lettre,Nbre]);

end;



Et voila ...



@ +++ Florent


Si tu ne te plantes pas ......
tu ne poussera jamais
Messages postés
1023
Date d'inscription
dimanche 1 août 2004
Statut
Membre
Dernière intervention
17 août 2008
1
Ma technique a cepandant une faille: si plusieurs lettres ont le meme
nmbre d'iterations, ce sera la derniere rencontrée qui sera affichée.



Mais bon, puisqu'il en faut une, cela n'a pas grande importance

Quoique ....



@ ++

Flo

Si tu ne te plantes pas ......
tu ne poussera jamais
Messages postés
6
Date d'inscription
samedi 29 janvier 2005
Statut
Membre
Dernière intervention
12 février 2005

Bonjour,

Je vous remercie pour votre rapidité mais il y'a quelque chose que je ne comprend pas dans les réponses.
Et c'est promis, je ferais un "réponse acceptée" dés que je serais chez moi, c'est à dire le week-end.



Tout d'abord pour les première solutions, crée un tableau avec les lettres de l'alphabet, coment faut-il que je me démerde exactement
Faire une variable de ce genre : Alphabet: Array[a, b, c...] of string; et que je le mette dans la variable général (avec le Form1: TForm1;) ?



Ensuite je n'ai pas compris comment est-ce que la fontion ci-dessous peut arriver à compter le nombre de caractère, les reconnaitres, incrémentation, etc.
Pourriez-vous m'expliquer un peu s'il vous plait

for i:=1 to Length(S) do
  begin
    Inc(Occurences[S[i]]); // On incrémente.
  
end;





Et quelle est selon vous la meilleur solution, la 1ere ou la 2nd



Merci d'avance.
Messages postés
1023
Date d'inscription
dimanche 1 août 2004
Statut
Membre
Dernière intervention
17 août 2008
1
Hello,



Alors en ce qui concerne le tableau, c'est vrai que cela n'est pas une syntaxe que l'on a l'habitude de voir.

Pour creer un tableau de toutes les lettres de l'alphabet, il faut
déclarer un type puis une variable localement (c-à-d dans une
procedure).



Regardes plutot:

procedure TForm1.FormCreate(Sender: TObject);

type

  TLettresAlphabet = array['A'..'Z'] of Integer; // Un tableau d'entier représentant les lettres

var

  Caracteres: TLettresAlphabet; // La variable en elle même

begin

  // ici tu en fait ce que tu veux

end;


Evidemment, tu crees ton type dans la procedure ou tu en as besoin. ;-)



Mon array[Char] of
Integer reprend le même principe sauf qu'il inclue toutes les lettres
disponibles (barres obliques, retour à la ligne, accents ...) Enfin
bref, tout ce qu'une variable de type Char peut recevoir.



Mais, pour ton utilisation, array['A'..'Z'] of Integer serait mieux que array[Char] of Integer car on ne perd pas de place pour ce que l'on a pas besoin.

Après pour le bout de code que tu as recopié, son fonctionnement est très simple.



Occurences étant un array['A'..'Z'] of Integer (c'est mieux ainsi), les numéros des cases ne sont pas des nombres comme pour un array[0..10] of Integer mais des ... Char !!

En gros, une case s'identifie par un caractère compris entre a et z.



Après il faut savoir que si S est une chaine ( string ), alors S[n] correspond au nieme caractere de cette chaine, le premier étant 1, le dernier étant Length(S).



Donc, avec cette boucle for, on
a successivement chaque caractere de la chaine. Comme les cases du
tableau sont identifiées par un caractère, on a accès à la case qui
correspond à la lettre en cours !!! Et comme cela, on incrémente le
nombre d'occurences de cette lettre.



Magique non ????

Donc, à la fiin de cette boucle, on a dans le tableau le nombre d'occurences de chaque lettre dans la chaine.



Il suffit de repassser en vue ce tableau pour trouver le nombre le plus grand.

Sauf que vu que les cases sont identifiées par un Char, il faut que la variable de controle soit ... un Char !!


Avec ces changements au niveau de la structure du tableau, voila la procedure modifiée :



procedure OccurenceLettrePlusPresente(S: string; var Lettre: Char; var Nbre: Integer);

var

  i: Integer;

  C, Max: Char;

  Occurences: array ['A'..'Z'] of Integer;

begin

  FillChar(Occurences,SizeOf(Occurences),0);   // On initialise tout à zéro

  S:=AnsiUpperCase(S); // Pour ignorer la casse.



  for i:=1 to Length(S) do

    Inc(Occurences[S[i]]); // On incrémente.



  Max:='A'; // Par défaut, le premier



  { Recherche du plus grand. }

  for C:=Low(Occurences) to High(Occurences) do

    if Occurences[C] > Occurences[Max] then

      Max:=C;



  Lettre:=Max;

  Nbre:=Occurences[Max];

end;


Personnellement, je trouve que ma
procedure est plus efficace car celle de ni69, incomplete,
necessiterait que la chaine soit parcourue 26 fois au lieu d'une pour
la mienne.

Celle de sim51 reprends l'idée de ni69 avec sa boucle for i:=1 to 26, et, donc, n'est pas plus performante.



En ce qui concerne les accents, la fonction de grandvizir que te
propose ni69 n'est pas très performante. Je posterai une source dès que
j'aurais fini de travailler la mienne.

Cepandant, tu peux l'inclure avant le traitement de la chaine, c-à-d au tout début de la procedure.



Allez, bonne chance, mais tu es dans la bonne voie



@ ++ Florent



Si tu ne te plantes pas ......
tu ne poussera jamais