Evaluation d'une chaîne de caractères formée d'une somme de nombres

 

Soit une chaîne de caractères du type "s:='5+3+4+7';";faisons le programme qui évalue cette chaîne de caractères.

Voyons l'algorithme de cette procédure :

- d'abord on sait que la valeur d'une chaîne vide est 0

- ensuite on sait évaluer un nombre seul avec la fonction "strToInt".

- on sait extraire une sous-chaîne avec la fonction "copy" et nous allons extraire des caractères jusqu'au premier signe "+"

- l'évaluation de la chaîne initiale est égale à la valeur du nombre extrait plus la valeur de la chaîne restante (appel récursif).

 

Voici le programme correspondant :

 

function eval(st: string): integer;
var a, i: integer;
begin
  if length(st) = 0 then
    eval := 0
  else
  begin
    i := 1;
    repeat inc(i)until (i > length(st)) or (st[i] = '+');
    a := strToInt(copy(st, 1, i - 1));
    delete(st, 1, i - 1);
    eval := a + eval(st)
  end;
end;
 

On appelle cette fonction de la façon suivante :

b:=eval('+51+7+67+31');

 

Vers une mini-calculatrice

 

Soit une chaîne de caractères du type "s:='5+3*4/2-5*3+4*7/2';";faisons le programme qui évalue cette chaîne de caractères.

La première chose à faire est la séparation des termes; on doit en effet extraire tous les termes qui sont séparés par des "+" et des "-".

Ensuite nous devons évaluer chacun des termes extraits, pour arriver à la fin à une somme (ou à une différence) de termes.

Pour commencer, on suppose qu'on doit évaluer une somme (ou une différence) de termes. Pour cela, nous reprenons le programme fait précédemment, et nous l'enrichissons, de façon à ce qu'il puisse évaluer aussi les différences.

 

function eval(st: string): integer;
var a, i: integer;
begin
  if length(st) = 0 then
    eval := 0
  else
  begin
    i := 1;
    repeat inc(i)until (i > length(st)) or (st[i] in ['+', '-']);
    a := strToInt(copy(st, 1, i - 1));
    delete(st, 1, i - 1);
    eval := a + eval(st)
  end;
end;

 

Maintenant, on doit créer la procédure qui évalue une expression formée uniquement de produits et quotients; ici, on ne peut pas appliquer la même méthode : pour les sommes, on évaluait le premier terme auquel on ajoutait le résultat du reste.

Mais avec les produits et les quotients, c'est différent : en effet, si on veut évaluer le résultat de "12/4*6/2" on ne peut pas dire qu’il est égal à la valeur du premier terme "12" divisé par la valeur du reste "4*6/2". Le résultat est en réalité "((12/4)*6)/2" soit 9.

Il faut donc lire non pas de gauche à droite, mais de droite à gauche.

Ainsi le résultat de "12/4*6/2" est égal au résultat de "12/4*6" divisé par 2.

   Le résultat de "12/4*6" est égal au résultat de "12/4" multiplié par 6

      Le résultat de "12/4" est égal au résultat de "12" divisé par 4.

      On peut évaluer cette expression, soit 3.

   On a, en remontant dans les appels récursifs, 3*6=18.

On a, en remontant encore une fois dans les appels récursifs, 18/2=9.

L'algorithme est le suivant :

- on lit une expression de la droite vers la gauche.

- si on est sur un signe "*" alors :

     - on extrait le dernier nombre de la chaîne

     - on évalue la chaîne restante

     - le résultat est égal à l'évaluation de la chaîne restante (appel récursif) multipliée par le dernier nombre

- si on est sur un signe "/" alors :

     - on extrait le dernier nombre de la chaîne

     - on évalue la chaîne restante

     - le résultat est égal à l'évaluation de la chaîne restante (appel récursif) divisée par le dernier nombre

- si on est au début de la chaîne (aucune multiplication, ni division) alors :

     - le résultat est égal à l'évaluation du nombre.

Voici le programme qui évalue une expression mathématique contenant des nombres entiers et les 4 opérations mathématiques. Ce programme fonctionne avec des nombres entiers. Ainsi, quand vous faites une division, si elle ne tombe pas juste, le résultat est arrondi, grâce à la fonction "div". Mais la transformation en réels est très facile.

 

function eval0(st: string): integer;
var a, i: integer;
  signe: char;
begin
  i := length(st);
  repeat dec(i)until (i = 0) or (st[i] in ['*', '/']);
  a := strToInt(copy(st, i + 1, length(st) - i));
  if i > 0 then signe := st[i] else signe := #0;
  delete(st, i, length(st) - 1 + i);
  if signe = '*' then eval0 := eval0(st) * a else
    if signe = '/' then eval0 := eval0(st) div a else
      eval0 := a;
end;
 
function eval(st: string): integer;
var a, i: integer;
begin
  if length(st) = 0 then
    eval := 0
  else
  begin
    i := 1;
    repeat inc(i)until (i > length(st)) or (st[i] in ['+', '-']);
    a := eval0(copy(st, 1, i - 1));
    delete(st, 1, i - 1);
    eval := a + eval(st)
  end;
end;

 

Télécharger le code source Delphi