String in Zahlen zerlegen

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Benutzeravatar
Roland Chastain
Beiträge: 156
Registriert: Sa 7. Jul 2012, 21:50
Wohnort: Saargemünd
Kontaktdaten:

Re: String in Zahlen zerlegen

Beitrag von Roland Chastain »

Hallo! Da ist eine andere Möglichkeit.

Code: Alles auswählen

 
program zahlen;
 
{$APPTYPE CONSOLE}
{$IFDEF FPC}{$MODE DELPHI}{$ENDIF}
 
uses
  RegExpr;
 
const
  SUBJECT = '1234 5678 9012 111.111 222.222 333.333';
  PATTERN = '\d+(\.\d+)?';
 
var
  expr: TRegExpr;
 
begin 
  expr := TRegExpr.Create;
  expr.Expression := PATTERN;
 
  if expr.Exec(SUBJECT) then
    repeat
      WriteLn(expr.Match[0]);
    until not expr.ExecNext;
 
  expr.Free;
  ReadLn;
end.
 
Petit poisson deviendra grand,
Pourvu que Dieu lui prête vie.

Mathias
Beiträge: 6162
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: String in Zahlen zerlegen

Beitrag von Mathias »

Das Splitten geht noch einfacher.

Code: Alles auswählen

function StrToVecIntSplit(ins: string): TIntArray;
var
  i, e: integer;
  sa: TStringArray;
begin
  sa := ins.Split(' ');
  SetLength(Result, Length(sa));
  for i := 0 to Length(sa) - 1 do begin
    Val(sa[i], Result[i], e);
  end;
end


Wurde dies mit fpc 3.0 eingeführt ?

Ein Wermutstropfen hat es doch.

Code: Alles auswählen

StrToVecInt('4 5 6 7 8 34 56')
ohne Probleme.

Aber wen es noch Leerzeichen vor dem String hat, wird es fehlerhaft.

Code: Alles auswählen

StrToVecInt('     4 5 6 7 8 34 56')


Mit StringList geht es auch mit vorangestellten Leerzeichen.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

BeniBela
Beiträge: 308
Registriert: Sa 21. Mär 2009, 17:31
OS, Lazarus, FPC: Linux (Lazarus SVN, FPC 2.4)
CPU-Target: 64 Bit

Re: String in Zahlen zerlegen

Beitrag von BeniBela »

Es geht auch super einfach mit meinen Internet Tools:


Code: Alles auswählen

 
uses xquery;
query('tokenize(normalize-space($_1), " ")!xs:decimal(.)', ['      4 5 6 7 8 34 56'])
 

marcov
Beiträge: 1100
Registriert: Di 5. Aug 2008, 09:37
OS, Lazarus, FPC: Windows ,Linux,FreeBSD,Dos (L trunk FPC trunk)
CPU-Target: 32/64,PPC(+64), ARM
Wohnort: Eindhoven (Niederlande)

Re: String in Zahlen zerlegen

Beitrag von marcov »

strtofloat ist relativ teuer, also ein bisschen Overhead ist nicht so Schlimm.

Das größere Problem aber ist das es kein "ex" Variante gibt die eine Zahl an einer bestimmte Position lesen können ohne Kopieren nach eine separater String. Das macht Speicher Belegung fast immer notwendig. VAL kann eben vom Anfang lesen, und aus "code" kann man lesen wie weit es gekommen ist, also eine val/delete Schleife wäre möglich. Ungetestet:

Code: Alles auswählen

ind:=0;
repeat
  val (s,zahl,code);
  if code<>1 then  // conflict auf erster zahl
     begin
        zahlen[ind]:=zahl;
        inc(ind);
        if code>0 then delete(s,1,code-1);
     end;
until code=0
  


Ich bin mir nicht ganz sicher was passiert wenn (1) der String lehre ist. (2) der letzter Zahl konvertiert wird. Ich weiß auch nicht ob dies so viel schneller ist. Tokenize ähnliche Lösungen (TStringlist inklusive) machen aber immer Mehrere Speicherbelegungen weil es nur ein Notwendig ist.

p.s. Ich habe noch Assembler Routine für den integer Fall aus FPC 0.99.5 bis 0.99.10 Zeiten (http://www.stack.nl/~marcov/xtdfpc/ und dann xtdfpc19.zip. Es ist nicht ohne Modifikationen mit 2.0+ verwendbar, und nutzt asm Opcodes die heute nicht mehr Modisch sind wie aam ). Früher war nicht immer alles besser :-)

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: String in Zahlen zerlegen

Beitrag von Warf »

man könnte auch einfach selbst durch den string Wandern ohne irgendwelche kuriosen gebilde um TStrings o.ä. zu bauen:

Code: Alles auswählen

 
type
  TIntArray = array of Integer;
 
function ReadNumbers(s: String): TIntArray;
var i, x, p: Integer;
begin
  SetLength(Result, Length(s)); // Maximaler Speicher aproximieren
  x:=Length(s)-1; // Maximalindex des Array
  p:=1; // Potenzfaktor
  FillChar(Result[0], SizeOf(Integer)*(x+1), #00); // 0 Initialisieren
  for i:=Length(s) downto 1 do // Durchwandern
    if s[i] in ['0'..'9'] then
    begin
      Result[x]+=p*(ord(s[i])-ord('0'));
      p:=p*10;
    end
    else if p>1 then
    begin
      dec(x);
      p:=1;
      end;
  if Result[x] = 0 then
    inc(x);
  // Array auf benötigte Größe verkleinern
  Move(Result[x], Result[0], (Length(Result)-x)*SizeOf(Integer));
  SetLength(Result, Length(Result)-x-1);
end;

Mathias
Beiträge: 6162
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: String in Zahlen zerlegen

Beitrag von Mathias »

Mit Integer wird dies gehen, aber sobald man es mit Float machen muss, wird es kompliziert.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: String in Zahlen zerlegen

Beitrag von Warf »

Mathias hat geschrieben:Mit Integer wird dies gehen, aber sobald man es mit Float machen muss, wird es kompliziert.


Naja das ist nur eine abfrage mehr:

Code: Alles auswählen

 
type
  TFloatArray = array of double;
 
function ReadFloats(s: string): TFloatArray;
var
  i, x, p: integer;
begin
  SetLength(Result, Length(s)); // Maximaler Speicher aproximieren
  x := Length(s) - 1; // Maximalindex des Array
  p := 1; // Potenzfaktor
  FillChar(Result[0], SizeOf(double) * (x + 1), #00); // 0 Initialisieren
  for i := Length(s) downto 1 do // Durchwandern
    if s[i] in ['0'..'9'] then
    begin
      Result[x] += p * (Ord(s[i]) - Ord('0'));
      p := p * 10;
    end
    else if (s[i] = '.') and (P > 1) then
    begin //Geteilt durch die letzte Potenz * 10 um es hinter das komma zu verschieben
      Result[x] := Result[x] / p;
      p := 1;
    end
    else if (s[i] = '-') and (Result[x] <> 0) then
      Result[x] := -Result[x]
    else if Result[x] <> 0 then
    begin
      Dec(x);
      p := 1;
    end;
  if Result[x] = 0 then
    Inc(x);
  // Array auf benötigte Größe verkleinern
  Move(Result[x], Result[0], (Length(Result) - x) * SizeOf(double));
  SetLength(Result, Length(Result) - x - 1);
end;

Mathias
Beiträge: 6162
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: String in Zahlen zerlegen

Beitrag von Mathias »

Nur ist dies langsam ein bisschen viel Code, für diese einfache Function.
Mit Split bracht es nur 3 Zeilen, wen man das begin und end bei der for-Schleife weglässt.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: String in Zahlen zerlegen

Beitrag von Warf »

Mathias hat geschrieben:Nur ist dies langsam ein bisschen viel Code, für diese einfache Function.
Mit Split bracht es nur 3 Zeilen, wen man das begin und end bei der for-Schleife weglässt.

Man hat im worst Vase aber eine laufzeitkomplexität von n! Während meins eine Laufzeitkomplexität von n hat, das heißt auf großen bzw vielen Eingaben ist das ein Ganzes Stück schneller (und meins ist dazu noch nahezu inplace) kommt halt drauf an, braucht man schnell eine Lösung ist das über split wohl das beste, aber wenn man es oft verwendet würde ich schon meinen Code verwenden

BeniBela
Beiträge: 308
Registriert: Sa 21. Mär 2009, 17:31
OS, Lazarus, FPC: Linux (Lazarus SVN, FPC 2.4)
CPU-Target: 64 Bit

Re: String in Zahlen zerlegen

Beitrag von BeniBela »

Wenn man es schnell haben will, braucht man eine Implementierung mit SSE

Oder mehrere Threads. Sollte sich gut aufteilen lassen

Antworten