String Nummerisch aufarbeiten

jkallup

Erfahrenes Mitglied
Hallo,

wollte mal schnell eben eine mathe unit schreiben - mit mässigen Erfolg.
Es sollen unterschiedlich Integer Werte, die als String repräsentiert werden
bearbeitet werden.

Also eine beliebige Menge an Daten - sofern Datenspeicher ausreicht.
Damit man einen Einstieg hat, habe ich nur Addition aufgenommen.
scheitere aber damit, die Strings richtig zu kombinieren.

irgendwie komm ich nicht weiter.

Für sachdienliche Hinweise bin ich Jedem dankbar.

Code:
unit Compiler;

interface

uses SysUtils, StrUtils, Classes, Dialogs, Contnrs;

procedure CompileAndRun(_Code: String);
procedure commenteof;
procedure ungetchar;
function getchar: Char;

var pc: Integer;
    line_no: Integer;
    Code: Array of Char;

type
    EMyErrorException = class(Exception);
    EMyEndOfComment   = class(Exception);


    TNumberStack = class(TStack);
    TNumberClass = class(TObject)
      FnumberStr : String;
      Fop        : Char;
    end;

var
  num_digit: String;
  num_class: TNumberClass;
  num_stack: TNumberStack;

  flag: Integer;

implementation

procedure commenteof;
begin
    ShowMessage(Format('unexpected EOF inside comment at line %d',
    [line_no]));
end;
procedure warn(err: String);
begin
    ShowMessage('Error:' + IntToStr(Line_no) + err);
end;
procedure fatal(err: String);
begin
    warn(err);
end;

function getchar: Char;
begin
  if pc > High(Code) then
  raise EMyErrorException.Create('Error:' + IntToStr(line_no) + ': Syntax Error');
  result := Code[pc];;
  inc(pc);
end;
procedure ungetchar;
begin
  if pc > 0 then
  begin
    dec(pc);
  end;
end;

procedure CompileAndRun(_Code: String);
var
  c, mop: Char;
  st,s1,s2: String;
  a1,a2: Array [0..4096] of Char;
  i: Integer;

type
  TTokenType = (tUnknown, tNumeric, tIdent, tMathOp);

  function skip_white_spaces: Char;
  label l1;
  begin
  result := #0;
  repeat
    c := getchar;
    if (c in ['0'..'9']) or (c in ['A'..'Z']) or (c in ['a'..'z'])
    or (c in ['+','-']) then
    begin
      result := c;
      exit;
    end else if c = #0 then break;
    if c = #13 then
    begin
      inc(line_no);
    end else if c = '/' then
    begin
      c := getchar;
      if c = #0 then
      begin
        commenteof;
        break;
      end else if c = '*' then
      begin
        l1:
        c := getchar;
        if c = #0 then
        begin
          commenteof;
          break;
        end else if c = '*' then
        begin
          c := getchar;
          if c = '/' then
          begin
            result := skip_white_spaces;
            exit;
          end else goto l1;
        end else   goto l1;
      end else if c = '/' then
      begin
        repeat
          c := getchar;
        until c in [#0,#10,#13];
        if c = #0 then break
        else if c = #13 then
        begin
          inc(line_no);
        end;
      end;
    end;
  until c = #0;
  result := c;
  end;

  function getIdent: TTokenType;
  begin
  end;

  function calculate(op: Char; v: TNumberStack): String;
  var s,s4: String;
      i,f1,f2,f3,f4,f5,f6,rest: integer;
      ptr1,ptr2: Pointer;
      ic: Integer;
  begin
    ptr1 := TNumberStack(v.PopItem);
    ptr2 := TNumberStack(v.PopItem);

    s1 := TNumberClass(ptr1).FnumberStr;
    s2 := TNumberClass(ptr2).FnumberStr;

    if op = '+' then
    begin
      if Length(Trim(s1)) = Length(Trim(s2)) then
      begin
          s1 := ReverseString(s1);
          s2 := ReverseString(s2);

          StrLCopy(PChar(@a1[0]), PChar(s1), High(a1));
          StrLCopy(PChar(@a2[0]), PChar(s2), High(a2));


          ic := 0;
          while true do
          begin
            if ic = 2 then break;

            f1 := integer(a1[ic]) - 48;
            f2 := integer(a2[ic]) - 48;
            f3 := f2 + f1;
            f4 := f3 - 10; // 2
            f5 := f4 - f3;

            if f5 < -9 then
            begin
              f6 := ((integer(a1[ic+1]) - 48) + 1) + 48;  // 1
            end;

            a1[ic] := chr(f4);
            a2[ic+1] := char(f6);

            showmessage(
            '1: ' + IntToStr(f1) + #10 +
            '2: ' + IntToStr(f2) + #10 +
            '3: ' + IntToStr(f3) + #10 +
            '4: ' + IntToStr(f4) + #10 +
            '5: ' + IntToStr(f5) + #10 +
            '6: ' + IntToStr(f6) + #10 +
            '7: ' + a2[ic+1]
            );

            inc(ic);
          end;
      end
      else if Length(s1) > Length(s2) then
      begin
        s := StringOfChar('0',
        Length(s1)   -
        Length(s2)) + s2;
      end;
    end;
    result := '1111';;
  end;

  function getNumber: String;
  begin
    c := skip_white_spaces;
    while c in ['0'..'9'] do
    begin
      num_digit :=
      num_digit + c;
      c := getchar;
    end;
    result := num_digit;
  end;

  function getExpression: String;
  begin
    s1 := getNumber;
    num_digit := '';
    if c = '+' then
    begin
      mop := '+';
      c  := skip_white_spaces;
      if c in ['0'..'9'] then
      begin
        s2 := c + getNumber + c;

        num_class := TNumberClass.Create;
        num_class.FnumberStr := s1[1];
        num_class.Fop := mop;
        num_stack.PushItem(num_class);

        num_class := TNumberClass.Create;
        num_class.FnumberStr := s2[1];
        num_class.Fop := mop;
        num_stack.PushItem(num_class);

        s2 := calculate(mop,num_stack);
      end;
    end;

    s2 := s2 + c;
    showmessage('A-->>> ' + s1);

    num_class := TNumberClass.Create;
    num_class.FnumberStr := s1[1];
    num_class.Fop := mop;
    num_stack.PushItem(num_class);

    if flag = 2 then
    begin
      s2 := calculate(mop,num_stack);
      flag := 0;
    end else inc(flag);
    result := num_digit;
  end;

begin
  pc := 0;
  Line_no := 1;

  try
    SetLength(Code,Length(_code));
    StrLCopy(PChar(@code[0]), PChar(_code), High(code));

    num_class := TNumberClass.Create;
    num_stack := TNumberStack.Create;

    num_class.FnumberStr := '<null>';
    num_stack.PushItem(num_stack);

    flag := 0;

    for i := 0 to High(a1) do a1[i] := '0';
    for i := 0 to High(a1) do a2[i] := '0';

    repeat
      num_digit := '';
      c := skip_white_spaces;
      if c in ['0'..'9'] then
      begin
        ungetchar;
        s1 := getExpression;
      end;
    until c = #0;
  except
    on E: EMyEndOfComment do
    begin
    end;
    on E: EMyErrorException do
    begin
      ShowMessage('Error:' + IntToStr(line_no) + ': ' + E.Message);
    end;
  end;
end;

end.
 

vfl_freak

Premium-User
Moin,

... scheitere aber damit, die Strings richtig zu kombinieren. Irgendwie komm ich nicht weiter ...
aha, und was heißt das genau ?? :(
Stell' doch bitte konkrete Frage - schließlich können wir nicht ahnen, WO Du ein Problem hast !!

Gruß Klaus
 

jkallup

Erfahrenes Mitglied
Also,
gegeben sind 3 Strings.
s9 := '710';
s8 := '521';
s7 := '010';

Code:
      s9 := ReverseString(s8);
      s8 := ReverseString(s1);
      s7 := ReverseString(s7);
      s7 := Trim(Copy(s7,5,Length(s7)));

wie kann man dann nach diesen Angaben die drei Strings (bereits formatiert)
so bearbeiten, dass man eine Addition machen kann.
Bei richtiger Bearbeitung soll dann wiederrum ein vierter String als Summe/Ergebnis
entstehen.
Das Resultat sollte dann also: "231" sein.
 

jkallup

Erfahrenes Mitglied
sodele,

ich habe den code nochmals überarbeitet.
er scheint bei einer addition mit den beiden string inhalten "215" + "17" zu funktionieren.

showmessage(inttostr(ord(u1[0]))+#10+u2[0]+#10+inttostr(ord(m1[0]))+
#10+s1+#10+s2);

m1 scheint auch so weit inordnung zu sein.
man müsste jetzt nur noch reversestring machen, wenn da nicht die viellen nullen
wären.
wie kann man diese abschneiden?

ich suche also für pascal/delphi 7 eine funktion, die rückwärts die nullen abschneidet.
also im prinzip so:

nehme string
schaue ob an position(100) eine 0 steht
wenn ja, dann schaue an position(99), ist dort eine 0 dann abschneiden
wenn nicht (also > 0) dann beende schleife.
ansonsten wiederhole schleife bis position(1)

der string liegt zum beispiel in dieser form vor: 532000000
als zwischen ergebnis: 532
und als endergebnis: 235

wäre cool, wenn da jemand eine routine basteln kann.
danke und tschö


Code:
unit Compiler;

interface

uses SysUtils, StrUtils, Classes, Dialogs, Contnrs;

procedure CompileAndRun(_Code: String);
procedure commenteof;
procedure ungetchar;
function getchar: Char;

var pc: Integer;
    line_no: Integer;
    Code: Array of Char;

type
    EMyErrorException = class(Exception);
    EMyEndOfComment   = class(Exception);


    TNumberStack = class(TStack);
    TNumberClass = class(TObject)
      FnumberStr : String;
      Fop        : Char;
    end;

var
  num_digit: String;
  num_class: TNumberClass;
  num_stack: TNumberStack;

  flag: Integer;

implementation

procedure commenteof;
begin
    ShowMessage(Format('unexpected EOF inside comment at line %d',
    [line_no]));
end;
procedure warn(err: String);
begin
    ShowMessage('Error:' + IntToStr(Line_no) + err);
end;
procedure fatal(err: String);
begin
    warn(err);
end;

function getchar: Char;
begin
  if pc > High(Code) then
  raise EMyErrorException.Create('Error:' + IntToStr(line_no) + ': Syntax Error');
  result := Code[pc];;
  inc(pc);
end;
procedure ungetchar;
begin
  if pc > 0 then
  begin
    dec(pc);
  end;
end;

procedure CompileAndRun(_Code: String);
  const MaxBigInt = 2048;  // maximal digits (max string length)
var
  c, mop: Char;
  st,s1,s2: String;
  a1,a2, u1,u2: Array [0..MaxBigInt+1] of Char;
  i: Integer;

type
  TTokenType = (tUnknown, tNumeric, tIdent, tMathOp);

  function TrimLeadingZeros(const Value: string): string;
  var
    i: Integer;
  begin
    for i := 1 to Length(Value) do
      if Value[i]<>'0' then
      begin
        Result := Copy(Value, i, MaxInt);
        exit;
      end;
    Result := '0';
  end;

  function RightPad(S: string; Ch: Char; Len: Integer): string;
  var
    RestLen: Integer;
  begin
    Result  := S;
    RestLen := Len - Length(s);
    if RestLen < 1 then Exit;
    Result := StringOfChar(Ch, RestLen) + S;
  end;

  function LeftPad(S: string; Ch: Char; Len: Integer): string;
  var
    RestLen: Integer;
  begin
    Result  := S;
    RestLen := Len - Length(s);
    if RestLen < 1 then Exit;
    Result := S + StringOfChar(Ch, RestLen);
  end;

  function skip_white_spaces: Char;
  label l1;
  begin
  result := #0;
  repeat
    c := getchar;
    if (c in ['0'..'9']) or (c in ['A'..'Z']) or (c in ['a'..'z'])
    or (c in ['+','-']) then
    begin
      result := c;
      exit;
    end else if c = #0 then break;
    if c = #13 then
    begin
      inc(line_no);
    end else if c = '/' then
    begin
      c := getchar;
      if c = #0 then
      begin
        commenteof;
        break;
      end else if c = '*' then
      begin
        l1:
        c := getchar;
        if c = #0 then
        begin
          commenteof;
          break;
        end else if c = '*' then
        begin
          c := getchar;
          if c = '/' then
          begin
            result := skip_white_spaces;
            exit;
          end else goto l1;
        end else   goto l1;
      end else if c = '/' then
      begin
        repeat
          c := getchar;
        until c in [#0,#10,#13];
        if c = #0 then break
        else if c = #13 then
        begin
          inc(line_no);
        end;
      end;
    end;
  until c = #0;
  result := c;
  end;

  function getIdent: TTokenType;
  begin
  end;

  function calculate(op: Char; v: TNumberStack): String;
  var s,s4: String;
      i,f1,f2,f3,f4,f5,f6,rest: integer;
      ptr1,ptr2: Pointer;
      stmp,s7,s8,s9: String;
      ic,b1,i2: Integer;
      m1,m2: Array[0..4096] of integer;
  begin
    ptr1 := TNumberStack(v.PopItem);
    ptr2 := TNumberStack(v.PopItem);

    s1 := TNumberClass(ptr1).FnumberStr;
    s2 := TNumberClass(ptr2).FnumberStr;

    s1 := ReverseString(s1);
    s2 := ReverseString(s2);

    StrLCopy(PChar(@a1[0]), PChar(s1), High(a1));
    StrLCopy(PChar(@a2[0]), PChar(s2), High(a2));

    // --------------
    // math - add ...
    // --------------
    if op = '+' then
    begin
      // -------------------------------
      // first, collect informations ...
      // -------------------------------
      for b1 := 0 to MaxBigInt do
      begin
        m1[b1] := integer(a1[b1]) - 48; if m1[b1] < 0 then m1[b1] := 0;
        m2[b1] := integer(a2[b1]) - 48; if m2[b1] < 0 then m2[b1] := 0;

        f3 := m1[b1] + m2[b1];

        u1[b1] := chr(f3 div 10);
        u2[b1] := chr(f3 mod 10);
      end;

      // -----------------------------
      // then calculate array data ...
      // -----------------------------
      for b1 := 0 to MaxBigInt do
      s7 :=
      s7  + IntToStr(Integer(u1[b1]));

      // -----------------------
      // set rest wuth zeros ...
      // -----------------------
      s2 := ReverseString(s2);
      s2 := rightpad(s2,'0',MaxBigInt+(Length(s2)-Length(s2)));
      s8 := '';
      for b1 := 1 to MaxBigInt-1 do
      s8 := s8 + inttostr(integer(u1[b1])+integer(u2[b1]));
      s8 := ReverseString(s8);
      s8 := TrimLeadingZeros(s8);
      s8 := rightpad(s8,'0',MaxBigInt+(Length(s8)-Length(s8)));

      s1 := ReverseString(s2);
      s2 := ReverseString(s8);

      for b1 := 0 to MaxBigInt do begin
      u1[b1] := s1[b1+1];
      u2[b1] := s2[b1+1]; end;

      for b1 := 0 to MaxBigInt do m1[b1] := integer(ord(32));
      for b1 := 0 to MaxBigInt do m1[b1] := ((ord(u1[b1])-48) + (ord(u2[b1])-48));

      s1 := '';
      for b1 := 0 to MaxBigInt do
      s1 := s1 + inttostr(m1[b1]);

      showmessage(inttostr(ord(u1[0]))+#10+u2[0]+#10+inttostr(ord(m1[0]))+
      #10+s1+#10+s2);

      // -----------------------
      // strip leading zeros ...
      // -----------------------
      stmp := TrimLeadingZeros(s1);
    end;


    result := stmp;
  end;

  function getNumber: String;
  begin
    c := skip_white_spaces;
    while c in ['0'..'9'] do
    begin
      num_digit :=
      num_digit + c;
      c := getchar;
    end;
    result := num_digit;
  end;

  function getExpression: String;
  begin
    s1 := getNumber;
    num_digit := '';
    if c = '+' then
    begin
      mop := '+';
      c  := skip_white_spaces;
      if c in ['0'..'9'] then
      begin
        ungetchar;
        s2 := getNumber;

        num_class := TNumberClass.Create;
        num_class.FnumberStr := s1;
        num_class.Fop := mop;
        num_stack.PushItem(num_class);

        num_class := TNumberClass.Create;
        num_class.FnumberStr := s2;
        num_class.Fop := mop;
        num_stack.PushItem(num_class);


        s2 := calculate(mop,num_stack);
      end;
    end;
    result := s2;
  end;

begin
  pc := 0;
  Line_no := 1;

  try
    SetLength(Code,Length(_code));
    StrLCopy(PChar(@code[0]), PChar(_code), High(code));

    num_class := TNumberClass.Create;
    num_stack := TNumberStack.Create;

    num_class.FnumberStr := '<null>';
    num_stack.PushItem(num_stack);

    flag := 0;

    for i := 0 to High(a1) do a1[i] := char(integer(0)+(48));
    for i := 0 to High(a1) do a2[i] := char(integer(0)+(48));
    for i := 0 to High(u1) do u1[i] := char(integer(0)+(48));
    for i := 0 to High(u2) do u2[i] := char(integer(0)+(48));

    repeat
      num_digit := '';
      c := skip_white_spaces;
      if c in ['0'..'9'] then
      begin
        ungetchar;
        s1 := getExpression;
        ShowMessage(s1);
      end;
    until c = #0;

    num_stack.Free;
    num_class.Free;
  except
    on E: EMyEndOfComment do
    begin
    end;
    on E: EMyErrorException do
    begin
      ShowMessage('Error:' + IntToStr(line_no) + ': ' + E.Message);
    end;
  end;
end;

end.
 

ComFreek

Mod | @comfreek
Moderator
Hier ein einfacher Algorithmus in JavaScript, den du sicher nach Delphi portieren kannst:
Javascript:
function trim_and_reverse(str) {
    var result = 0;
    var takeResult = false;

    for (var i=str.length-1; i>=0; i--) {
        if (!takeResult && str[i] != "0") {
            takeResult = true;
        }
       
        if (takeResult) {
            result += Math.pow(10, i) * str[i];
        }
    }
    return result;
}

document.body.innerHTML = trim_and_reverse("5320000")

Es wird allerdings vorausgesetzt, dass ein Integer zurückgegeben werden muss. Wenn du einen String zurückgeben möchtest, sollte folgender Code funktionieren:

Javascript:
function trim_and_reverse(str) {
    var resultArray;
    var resultLength;
    var takeResult = false;

    for (var i=str.length-1; i>=0; i--) {
        if (!takeResult && str[i] != "0") {
            takeResult = true;
            resultLength = i + 1;
            result = []; // will eventually be of size resultLength
        }
       
        if (takeResult) {
            result[resultLength-i] = str[i]
        }
    }
    return result.join("");
}

document.body.innerHTML = trim_and_reverse("5320000")