Sammen med PolyPascal (ja det var tider <G>), var bl.a. souce til en Parser, som jeg selv har brugt et par gange (ja selv i dag i Delphi), så med mindre du lige har en PolyPascal liggende ved siden af din PC, vil jeg forsøge at grave soucen frem fra mine gemmer.
Download Turbopowers SysTools fra http://sourceforge.net/projects/tpsystools/ Den indeholder mange gode ting, bl.a. en expression evaluator (TStExpression). Så kan du gøre sådan: var i: Integer; begin StExpression1.Expression := '2232*343+123-12'; i := StExpression1.AsInteger; Edit1.Text := IntToStr(i); {eller} Edit2.Text := StExpression1.AsString; {=765687}
Det er meget besværligt, ikke noget man bare gør. Har selv forsøgt mange gange. Hvis det skal virke ordenligt, så skal man hente komponenter etc. Hvilket jeg selv synes er lidt trist, da man så ikke "selv" har lavet programmet.
Hm. Det lader til der er en del uenighed på området.
Overvejede om det ikke kunne lade sig gøre at opdele strengen i forskellige variabler, og der efter lave noget if() men regne opperatoren, men da jeg ikke er så programmeringskyndig vil jeg gerne have lidt bud.
Har ikke den store lyst til bareat smide en komponent ind, da jeg som stefmeister antyder ikke selvhar lavet programmet.
Problemet med if og copy er et det er nok nemt med de helt simple eksempler men det bliver hurtigt til noget spagetti når man skal have styr på det hele: - brug af parenterser - operator precedence
Vedlagte kode er som nævnt oprindelig fra PolyPascal (så det er måske Anders selv der har skrevet det <G>) og som du kan se i Kommentaren fik jeg "et sjovt problem" da jeg skulle anvende den i Delphi 3, og var derfor nødt til at omskrive den lidt (måske ikke længere nødvendigt). Den nederste funktion ("Calc") kan du ikke anvende som den er, men du kan bruge den som et eksempel på hvordan man kan lave en "wrapper" til Evaluate funktionen (I Calc fjerner jeg alle mellemrum, og laver "," om til ".", samt håndtere evt. Division Zero).
<SNIP> Procedure Evaluate(Var szExpr : String; Var fltValue : Float; Var iErrPos : integer); type stdf = (fabs,fsqrt,fsin,fcos,farctan,fln,fexp); stdflist = array[stdf] of string[6]; const stdfun : stdflist = ('ABS','SQRT','SIN','COS','ARCTAN','LN','EXP'); chErr = '?'; chEofLine = #13; var iPos : integer; ch : char;
Procedure NextChar; begin repeat iPos := iPos + 1; if iPos <= length(szExpr) then ch := szExpr[iPos] else ch := chEofLine; until ch <> ' '; end;
Function Expression : Float; var E : Float; Opr : char;
Function Simexpr : Float; var s : Float; opr : char;
Function Term : Float; var t : Float;
Function Signedfactor : Float;
Function Factor : Float; {Delphi 3.0 gives Internal Error: URW376 (Moved to outer function) type stdf = (fabs,fsqrt,fsin,fcos,farctan,fln,fexp); stdflist = array[stdf] of string[6]; const stdfun : stdflist = ('ABS','SQRT','SIN','COS','ARCTAN','LN','EXP'); } var p,e,sl : integer; found : boolean; f : Float; sf : stdf; begin if ch in ['0'..'9'] then begin p := iPos; repeat NextChar until not(ch in ['0'..'9','.'{DecimalSeparator}]); if ch in ['E','e'] then begin NextChar; if ch in ['+','-'] then NextChar; while ch in ['0'..'9'] do NextChar; end; val(copy(szExpr, p, iPos-p), f, e); if e<>0 then begin iPos := p + e - 1; ch := chErr; end; end else if ch='(' then begin NextChar; f := expression; if ch = ')' then NextChar else ch := chErr; end else if ch='X' then begin NextChar; f := fltValue; end else begin found := false; for sf := fabs to fexp do begin if not found then begin sl := length('stdfun[sf]'); if copy(szExpr, iPos, sl) = 'stdfun[sf]' then begin iPos := iPos + sl - 1; NextChar; f := factor; case sf of fabs : f := abs(f); fsqrt : f := sqrt(f); fsin : f := sin(f); fcos : f := cos(f); farctan : f := arctan(f); fln : f := ln(f); fexp : f := exp(f); end; found := true; end; end; end; if not found then ch := chErr; end; factor := f; end;
begin if ch = '-' then begin NextChar; signedfactor := -factor; end else begin signedfactor := factor; end; end;
begin t := signedfactor; while ch = '^' do begin NextChar; t := exp(ln(t)*signedfactor); end; term := t; end;
begin s := term; while ch in ['*','/'] do begin opr := ch; NextChar; case opr of '*' : s:=s*term; '/' : begin TempFloat := term; S := S / TempFloat; end; end; end; simexpr := s; end;
begin e := simexpr; while ch in ['+','-'] do begin opr := ch; NextChar; case opr of '+' : e := e + simexpr; '-' : e := e - simexpr; end; end; expression := e; end;
begin iPos := 0; nextchar; fltValue := expression; if (ch = chEofLine) then iErrpos := 0 else iErrpos := iPos; end;
Function Calc(szExpression : String) : Float; var fltRes : Float; iErrorPos : Integer; begin Try szExpression := StripCh(szExpression, ' '); szExpression := ReplaceCh(szExpression, ',', '.'); Evaluate(szExpression, fltRes, iErrorPos); Result := fltRes; if iErrorPos <> 0 then fltRes := 0; Except On EZeroDivide do Result := 0; end; end; </SNIP>
Det er måske udemærket at man vil lave det selv, i stedet for at bruge en komponent. Men så skal man da ikke spørge her, for så har man jo ikke lavet det selv?!?! Om man bruger en komponent som en anden har lavet eller bruger en procedure som en anden har lavet, hvad forskel gør det?? Der er vist noget her som jeg ikke forstår. Oh well ...
tolderlund -> hvis man får hjælp herinde, så kan man oftest spørge personen der har lavet det, om hvad der sker etc. plus det er nemmere selv at rette i koden. Hvis man bruger en komponent, så synes jeg ofte det er en masse mærkelige ting i koden, ofte mere end der egenlig er nødvendigt.
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.