Ce code permet de calculer une operation basique presentent dans une chaine de caractere, comme par exemple (3*5(10-2))/10 (qui renvoi 12)
Cependant il ne prend pas en compte les priorité de multiplications et de division, et donc 5+3*2 revien pour lui à 8*2 (pour lui faire comprendre faut faire 5+(3*2))
il gere aussi les float (type single), donc 3*3.33333333333 = 10 ou preske :P
je mets pas de zip, il suffit de faire un copier coller dans un fichier
Source / Exemple :
(*--------------------------------------------//
Calculatrice de chaines (resultat a virgule)
Par anK (legere modif. de Bestiol :))
Bug(s): lorsqu'on divise par 0... :D
//--------------------------------------------*)
unit Unit1;
interface
uses strUtils,sysUtils;
type
TOperation=(loAdd,loSub,loMul,loDiv);
function CalculStr(Str:String):Single;
const
Niveau_Parentheses=15;
implementation
function SimplifyStr(Str:string):string;
const
Smpl: Array[0..3]Of String = ('++', '--', '+-', '-+'); //: Tableau des doublons à simplifier
SmplPar: Array[0..3]Of String = ('+' , '+' , '-' , '-');//: Par quoi il faut les remplacer
var i: Integer;
begin
//ça bug encore si il y a --- ou +++ ect... mais a part ça c nikel ;)
//Plus maintenant ! ;o)
Result := Str;
for i := Low(Smpl) to High(Smpl) do
While Pos(Smpl[i], Result) > 0 do
Result := AnsiReplaceStr(Result, Smpl[i], SmplPar[i]);
Result := AnsiReplaceStr(Result, '*(', '(');
Result := AnsiReplaceStr(Result, '()','');
Result := AnsiReplaceStr(Result, ' ',''); //On comble les trous!
Result := AnsiReplaceStr(Result, '.',','); //Les . sont transformés en ,
end;
function CalculStr(Str:String):Single;
var
I,J:integer;
LastOperande: TOperation;
zPar: array[0..Niveau_Parentheses] of single; //Profondeur des parentheses
tPar: array[1..Niveau_Parentheses] of TOperation; //Type liason entre la parenthese et sa superieure
PeC: 0..Niveau_Parentheses; //Parenthese en Cours
fstOp: boolean; //Premier operateur
ActuNombre: boolean; //Si actuellement il y a un nombre...
TailleNombre: Word;
DebutNombre: Word;
StringTemp: string;
DejaVirgule: boolean; //Si le nombre a deja une virgule...
procedure CalculUneOperation;
var Nombre:single;
begin
Nombre:=StrtoFloat(Copy(StringTemp,DebutNombre,TailleNombre));
case LastOperande of
loAdd:
zPar[PeC]:=zPar[PeC]+Nombre;
loSub:
zPar[PeC]:=zPar[PeC]-Nombre;
loMul:
zPar[PeC]:=zPar[PeC]*Nombre;
loDiv:
zPar[PeC]:=zPar[PeC]/Nombre;
end;
end;
procedure StopNombre;
begin
DejaVirgule := False;
ActuNombre := False;
end;
procedure InitParenthese;
begin
end;
const
Nombre = ['0'..'9']; //On a dans nombre aussi le '.', mais il est comptabilisé differement :)
Signe = ['+','-','*','/'];
Parenthese = ['(',')'];
begin
//-------------Initialisation-----------------
LastOperande := loAdd;
fstOp := True;
PeC := 0;
zPar[0] := 0;
ActuNombre := False;
DejaVirgule := False;
//--------------------------------------------
StringTemp := SimplifyStr(Str); //Simplification des calculs (++ devient + ect...)
for I:=1 to Length(Str) do //Debut de la boucle
begin
//-------------Les Nombres -------------------
if StringTemp[I] in Nombre then
begin
if not ActuNombre then //Si un nombre n'est pas deja "Lancé"
begin
//On le "lance"
ActuNombre := True;
DebutNombre := I;
fstOp:=False;
end;
end;
//--------------------------------------------
//-------------La virgule --------------------
if StringTemp[I] = ',' then
begin
if (not DejaVirgule) and ActuNombre then
begin
//On rajoute la virgule au nombre deja lancé
DejaVirgule:=True; // =)
end else begin
//ERREUR dans la string meme...
end;
end;
//--------------------------------------------
//---------Parentheses ouvertes---------------
if StringTemp[I] = '(' then
begin
if ActuNombre then//Si ActuNombre = True alors on coupe le nombre...
begin
TailleNombre := I-DebutNombre;
ActuNombre := False;
CalculUneOperation; //On calcul la derniere operation
inc(PeC);
zPar[PeC] := 0; //on reinitialise l'interieur de la parenthese
//Donc si il y a un nombre k(x) on a k*x
tPar[PeC] := loMul;
//zPar[PeC] := 0;
//Comme dans toute parenthese, le FirstOperateur=true, et on commence par un add
LastOperande := loAdd;
fstOp := True;
end else
begin
inc(PeC);
zPar[PeC] := 0; //on reinitialise l'interieur de la parenthese
tPar[PeC] := LastOperande;//Le dernier operateur avant la parenthese
LastOperande := loAdd;
fstOp := True;
end;
end;
//---------Parentheses fermé---------------
if StringTemp[I] = ')' then
begin
//On s'assure la finalisation du dernier nombre de la parenthese
if ActuNombre then
begin
TailleNombre:=I-DebutNombre;
CalculUneOperation; //On finalise si jamais il resté un nombre...
end;
case tPar[PeC] of //On mets à jour la parenthese inferieur
loMul:zPar[PeC-1]:=zPar[Pec-1]*zPar[Pec];
loAdd:zPar[PeC-1]:=zPar[Pec-1]+zPar[Pec];
loSub:zPar[PeC-1]:=zPar[Pec-1]-zPar[Pec];
loDiv:zPar[PeC-1]:=zPar[Pec-1]/zPar[Pec];
end;
if ActuNombre then//Si ActuNombre = True alors on coupe le nombre...
begin
TailleNombre:=I-DebutNombre;
ActuNombre:=False;
CalculUneOperation; //On calcul la derniere operation
//Donc si il ya un nombre k(x) on a k*x
//LastOperande:=loMul; //Donc on multiplie ;)
end;
dec(PeC);
end;
//--------------------------------------------
//-------------Le signe Plus-----------------
if StringTemp[I] = '+' then
begin
if fstOp or (StringTemp[I-1] in ['*','/']) then //Si Premier calcul ou avant le - il y avait un * ou /
begin
//C'est le premier operateur, donc un debut de nombre...
if StringTemp[I+1] in Nombre then //On debute un nombre...
begin
fstOp := False;
ActuNombre := True;
DebutNombre := (I+1);//Sans prendre en compte le +
end;
end;
if ActuNombre then //Si un nombre est déja entrain d'etre lu
begin
ActuNombre := False; //On stoppe la lecture de ce nombre
TailleNombre := I-DebutNombre;
CalculUneOperation; //On calcul le dernier Operateur
LastOperande := loAdd; //On change ce dernier operateur :)
end;
if not fstOp then if StringTemp[I-1]=')' then //Si le dernier caractere été un ')' alors...
begin
//A la difference avec ActuNombre=true, on a ici pas de nombre, mais une parenthese...
//Donc pas de nombre à definir
LastOperande := loSub; //On change seulement ce dernier operateur :)
end;
end;
//--------------------------------------------
//-------------Le signe Moins-----------------
if StringTemp[I] = '-' then
begin
if ActuNombre then //Si un nombre est deja entrain d'etre lu
begin
ActuNombre := False; //On stoppe la lecture de ce nombre
TailleNombre := I-DebutNombre;
CalculUneOperation; //On calcul le dernier Operateur
LastOperande := loSub; //On change ce dernier operateur :)
end;
if fstOp or (StringTemp[I-1] in ['*','/']) then //Si Premier calcul ou avant le - il y avait un * ou /
begin
//C'est le premier operateur, donc un debut de nombre...
if StringTemp[I+1] in Nombre then //On debute un nombre...
begin
fstOp := False;
ActuNombre := True;
DebutNombre := I;
end;
end;
if not fstOp then if StringTemp[I-1]=')' then //Si le dernier caractere été un ')' alors...
begin
//A la difference avec ActuNombre=true, on a ici pas de nombre, mais une parenthese...
//Donc pas de nombre à definir
LastOperande := loSub; //On change seulement ce dernier operateur :)
end;
end;
//--------------------------------------------
//-------------Le signe Multiplication--------
if StringTemp[I] = '*' then
begin
if ActuNombre then //Si un nombre est deja entrain d'etre lu
begin
ActuNombre := False; //On stoppe la lecture de ce nombre
TailleNombre := I-DebutNombre;
CalculUneOperation; //On calcul le dernier Operateur
LastOperande := loMul; //On change ce dernier operateur :)
end;
if not fstOp then if StringTemp[I-1]=')' then //Si le dernier caractere été un ')' alors...
begin
//A la difference avec ActuNombre=true, on a ici pas de nombre, mais une parenthese...
//Donc pas de nombre à definir
LastOperande := loMul; //On change seulement ce dernier operateur :)
end;
end;
//--------------------------------------------
//-------------La Division--------------------
if StringTemp[I] = '/' then
begin
if ActuNombre then //Si un nombre est deja entrain d'etre lu
begin
ActuNombre := False; //On stoppe la lecture de ce nombre
TailleNombre := I-DebutNombre;
CalculUneOperation; //On calcul le dernier Operateur
LastOperande := loDiv; //On change ce dernier operateur :)
end;
if not fstOp then if StringTemp[I-1]=')' then //Si le dernier caractere été un ')' alors...
begin
//A la difference avec ActuNombre=true, on a ici pas de nombre, mais une parenthese...
//Donc pas de nombre à definir
LastOperande := loDiv; //On change seulement ce dernier operateur :)
end;
end;
//--------------------------------------------
end;
if ActuNombre then
begin
TailleNombre:=Length(StringTemp)-I;
CalculUneOperation; //On finalise si jamais il resté un nombre...
end;
Result:=zPar[0]; //On fou dans result le nombre trouvé...
end;
end.
Conclusion :
exemple d'utilisation: ShowMessage(Floattostr(CalculStr('8/10')));
Si jamais des bugs apparaissent (et il doit y en avoir) merci de me le dire :)
Vous n'êtes pas encore membre ?
inscrivez-vous, c'est gratuit et ça prend moins d'une minute !
Les membres obtiennent plus de réponses que les utilisateurs anonymes.
Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.
Le fait d'être membre vous permet d'avoir des options supplémentaires.