[gelöst] Im Editfeld eingabe: 34.56 -> absturz

Für Fragen von Einsteigern und Programmieranfängern...
Mathias
Beiträge: 6910
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Im Editfeld eingabe: 34.56 -> absturz

Beitrag von Mathias »

Wen du s meinst, das sind nicht einzelne Zeichen im String, sondern die Nummer des Stringes. s ist eine Array.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
theo
Beiträge: 10869
Registriert: Mo 11. Sep 2006, 19:01

Re: Im Editfeld eingabe: 34.56 -> absturz

Beitrag von theo »

Mathias hat geschrieben:Wen du s meinst, das sind nicht einzelne Zeichen im String, sondern die Nummer des Stringes. s ist eine Array.


Es ist schon richtig.
Dein Fehler: Man nennt ein Array of String nicht "s". Das ist verwirrend. Man nennt auch ein "double" nicht i.
Bei "StrArr" wäre das Missverständnis von m.fuchs nicht aufgetreten

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2808
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Im Editfeld eingabe: 34.56 -> absturz

Beitrag von m.fuchs »

Ah, da bitte ich um Entschuldigung, das habe ich wirklich übersehen bzw. nicht mit einem Array namens s gerechnet. Mea culpa.

Na schön, sehen wir uns dein Programm noch einmal an. Ich habe es mal ein wenig angepasst (so dass nicht immer das Array-Element selber überschrieben wird:

Code: Alles auswählen

program SpeedTest;
{$mode objfpc}{$H+}
 
uses
  Classes, SysUtils, Windows, StrUtils;
 
const
  max = 10000000;
 
function KommaInPunkt(var AString:string):string;
var
  i,l     :integer;
begin
  l:=Length(AString);
  if l>0 then for i:=1 to l do if AString[i]=',' then AString[i]:='.';
  Result:=AString;
end;
 
var
  i: integer;
  start,ende:cardinal;
  s: string;
  strArray:array[0..max]of string;
 
begin
  for i := 0 to max do begin
    strArray[i] := FloatToStr(Random * 1000000);
  end;
  WriteLn('Array filled.');
 
  start := GetTickCount;
  for i := 0 to max do begin
    s := Stringreplace(strArray[i],'.',',',[rfReplaceAll]);
  end;
  ende := GetTickCount;
  Writeln('Zeit StringReplace:', Ende-Start);
 
  start := GetTickCount;
  for i := 0 to max do begin
    s := KommaInPunkt(strArray[i]);
  end;
  ende := GetTickCount;
  Writeln('Zeit Komma in Punkt:', Ende-Start);
  readln;
end.
Es gewinnt: KommaInPunkt.

Nun ist leider das Ausgangstestmaterial nicht besonders gut. Es gibt nämlich kein Komma. Also wird auch nichts geändert.
Ändern wir mal die Erzeugung des Arrays ab:

Code: Alles auswählen

 for i := 0 to max do begin
    strArray[i] := FloatToStr(Random * 1000000) + ',' + FloatToStr(Random * 1000000);
  end;
Es gewinnt: StringReplace.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: Im Editfeld eingabe: 34.56 -> absturz

Beitrag von mse »

Solche Dinge machen doch immer wieder Spass! :-)
KommaInPunkt() verändert auch den Ursprungsstring was StringReplace() nicht macht. Dafür ist beim Aufruf von StringReplace() glaube ich ',' und '.' vertauscht, so dass es nicht viel zu tun gibt. MSEgui hat auch entsprechende Funktionen. Ich habe sie neu für Free Pascal optimiert, vorher waren sie für Delphi optimal. replacechar() bringt eine Kopie, replacechar1() arbeitet "in place". Der angepasste Test:

Code: Alles auswählen

 
program stringreplacetest;
{$ifdef FPC}{$mode objfpc}{$h+}{$endif}
{$ifdef mswindows}{$apptype console}{$endif}
uses
 {$ifdef FPC}{$ifdef unix}cthreads,cwstring,{$endif}{$endif}
 sysutils,strutils,msesysutils,mseformatstr,msenoise,msestrings;
 
const
  max = 10000000;
 
function KommaInPunkt(AString:string):string;
var
  i,l     :integer;
begin
  Result:= AString;
  l:=Length(result);
  if l>0 then for i:=1 to l do if result[i]=',' then result[i]:='.';
end;
 
var
 start,ende: longword;
 
procedure printresult(const caption: string);
begin
 writeln('Zeit '+caption+': '+ formatfloatmse((ende-start)/1000000,'0.0000 s'));
end;
 
var
  i: integer;
  s: string;
  strArray:array[0..max]of string;
 
begin
  for i := 0 to max do begin
   strArray[i]:= inttostr(mwcnoise() div 32)+','+
                                      inttostr(mwcnoise() div 32);
  end;
  WriteLn('Array filled.');
 
  start := timestamp(); //micro seconds
  for i := 0 to max do begin
    s := Stringreplace(strArray[i],',','.',[rfReplaceAll]);
  end;
  ende := timestamp();
  printresult('StringReplace');
 
  start := timestamp();
  for i := 0 to max do begin
    s := KommaInPunkt(strArray[i]);
  end;
  ende := timestamp();
  printresult('Komma in Punkt');
 
  start := timestamp();
  for i := 0 to max do begin
   s := replacechar(strArray[i],',','.');
  end;
  ende := timestamp();
  printresult('replacechar()');
 
  start := timestamp();
  for i := 0 to max do begin
   replacechar1(strArray[i],',','.');
  end;
  ende := timestamp();
  printresult('replacechar1()');
 
  readln;
end.
 
 

Code: Alles auswählen

 
Array filled.
Zeit StringReplace: 11.1018 s
Zeit Komma in Punkt: 3.1805 s
Zeit replacechar(): 2.4412 s
Zeit replacechar1(): 0.7440 s
 
Array filled.
Zeit StringReplace: 11.0746 s
Zeit Komma in Punkt: 3.1850 s
Zeit replacechar(): 2.4376 s
Zeit replacechar1(): 0.7394 s
 
Array filled.
Zeit StringReplace: 11.1084 s
Zeit Komma in Punkt: 3.1870 s
Zeit replacechar(): 2.4370 s
Zeit replacechar1(): 0.7396 s
 

Antrepolit
Beiträge: 340
Registriert: Di 12. Sep 2006, 08:57
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit
Kontaktdaten:

Re: Im Editfeld eingabe: 34.56 -> absturz

Beitrag von Antrepolit »

Code: Alles auswählen

for i := 0 to max do begin
    s := Stringreplace(strArray[i],'.',',',[rfReplaceAll]);
  end;
Das ist leider völliger Nonsense. StringReplace erwartet doch einen String als Input. Folglich muss man es nicht in einem for-Loop iterieren um eiun Array durchzunudeln:

Code: Alles auswählen

 
s := Stringreplace(strArray,'.',',',[rfReplaceAll]);
 
wäre das korrekte Äquivalent. Abgesehen davon wäre StringReplace imme noch schneller, da es bereits implementiert war und eben nicht alles bloß eine Frage der Laufzeit, sondern immer auch eine Frage der Designzeit ist. Es ärgert mich ja auch bloß, dass das Rad immer wieder neu erfunden wird, obwohl es annähernd fehlerfreien Code für derartige Aufgaben gibt.
Grüße, Antrepolit

care only if your os is really burning

Benutzeravatar
theo
Beiträge: 10869
Registriert: Mo 11. Sep 2006, 19:01

Re: Im Editfeld eingabe: 34.56 -> absturz

Beitrag von theo »

Dieser Thread driftet komplett ab.
Hab schon gar keine Lust mehr, zu den einzelnen Quatschbeiträgen Stellung zu nehmen.
Der letzte Beitrag von TE kromer war jedenfalls vorgestern um 14:21. :shock:

Heinrich Wolf
Beiträge: 323
Registriert: Di 12. Apr 2011, 13:21
OS, Lazarus, FPC: WinXP + VMWare Player mit Fedora14, L 1.1, FPC 2.7.1
CPU-Target: 1core 1,8GHz 32Bit
Wohnort: Fürth
Kontaktdaten:

Re: Im Editfeld eingabe: 34.56 -> absturz

Beitrag von Heinrich Wolf »

StringReplace ist ein sehr praktischer Einzeiler. Da braucht es keine Schleife mehr.

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

Re: Im Editfeld eingabe: 34.56 -> absturz

Beitrag von Mathias »

Gibt es eine Möglichkeit, dass das Programm bei keiner Variante abstürzt, also weder bei einer Kommazahl noch bei einer durch Punkt getrennten Zahl?
Es wurde noch was wichtiges übersehen wen die Umwandlung in DE und in CH funktionieren soll muss man zuerst den Decimalseperator prüfen.

Code: Alles auswählen

function GetDeci(const s: string): string;
begin
  Result := s;
  if DecimalSeparator = '.' then begin
    Result := StringReplace(Result, ',', '.', [rfReplaceAll]);
  end else if DecimalSeparator = ',' then begin
    Result := StringReplace(Result, '.', ',', [rfReplaceAll]);
  end;
end;  
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

wp_xyz
Beiträge: 5139
Registriert: Fr 8. Apr 2011, 09:01

Re: Im Editfeld eingabe: 34.56 -> absturz

Beitrag von wp_xyz »

Gibt es eine Möglichkeit, dass das Programm bei keiner Variante abstürzt, also weder bei einer Kommazahl noch bei einer durch Punkt getrennten Zahl?
Am besten, ohne StringReplace etc., mit den FormatSettings; allerdings darf der String keine Tausendertrennzeichen enthalten, die bei uns Punkte sind und sonst Kommas, also dem Dezimaltrennzeichen in die Quere kommen:

Code: Alles auswählen

 
function ConvertStrToNumber(const AString: String; out Number: Double; out Msg: String): boolean;
var
  fs: TFormatSettings;
begin
  Msg := '';
  Result := true;
  // Konvertierungsversuch mit aktuellen Einstellungen
  if TryStrToFloat(AString, Number) then 
    exit;
  // Konvertierungsversuch mit geänderten Einstellungen (Punkt und Komma vertauscht)
  fs := DefaultFormatSettings;
  if fs.DecimalSeparator := '.' then fs.DecimalSeparator := ',' else fs.Decimal.Separator := '.';
  if TryStrToFloat(AString, Number, fs) then
    exit;
  Result := false;
  Msg := 'Der String "' + AString +'" ist keine gültige Zahl.';
end;
 

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

Re: Im Editfeld eingabe: 34.56 -> absturz

Beitrag von Mathias »

Code: Alles auswählen

 allerdings darf der String keine Tausendertrennzeichen enthalten, die bei uns Punkte sind und sonst Kommas, also dem Dezimaltrennzeichen in die Quere kommen:
Irgendwie finde ich dies recht mühsam, warum hat man dafür nicht eine internationale Lösung ?
Warscheinlich kommt das Ganze aus dem Office-Bereich.
Zum Glück ist wenigstens bei den Programmiersprachen der Dezimalseperator einheitlich.

Ich habe auch erst kürzlich erfahren, das die Deutschen die Dezimaltrennung mit einem ',' machen.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Antrepolit
Beiträge: 340
Registriert: Di 12. Sep 2006, 08:57
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit
Kontaktdaten:

Re: Im Editfeld eingabe: 34.56 -> absturz

Beitrag von Antrepolit »

Mathias hat geschrieben:(...)
Irgendwie finde ich dies recht mühsam, warum hat man dafür nicht eine internationale Lösung ?
Doch. Mann muss nur die korrekten Eingabeelemente wie z.B. TFlostSpinEdit verwenden.
Mathias hat geschrieben: Warscheinlich kommt das Ganze aus dem Office-Bereich.
(...)
Es gibt fertige Lösungen. Doch irgendwie scheint jeder lieber seinen eigenen Spaghetti-Bastelcode ins Netz stellen zu wollen, der nicht fehlerfrei ist und auch nur Teile des problems löst, statt die fertige, korrekte Lösung verwenden zu wollen. Von daher hat Theo recht, dieser Thread driftet komplett ab.
Grüße, Antrepolit

care only if your os is really burning

wp_xyz
Beiträge: 5139
Registriert: Fr 8. Apr 2011, 09:01

Re: Im Editfeld eingabe: 34.56 -> absturz

Beitrag von wp_xyz »

Mann muss nur die korrekten Eingabeelemente wie z.B. TFlostSpinEdit verwenden.
Wenn aber die Frage ist, wie man Punkt UND Komma als gültige Dezimaltrennzeichen ermöglichen kann (siehe erstes Posting --> kein Abdriften!), dann kann TFloatSpinEdit auch nicht helfen.

Antrepolit
Beiträge: 340
Registriert: Di 12. Sep 2006, 08:57
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit
Kontaktdaten:

Re: Im Editfeld eingabe: 34.56 -> absturz

Beitrag von Antrepolit »

wp_xyz hat geschrieben:(...)Wenn aber die Frage ist, wie man Punkt UND Komma als gültige Dezimaltrennzeichen ermöglichen kann (siehe erstes Posting --> kein Abdriften!), dann kann TFloatSpinEdit auch nicht helfen.
Das war nicht die Frage.
kromer hat geschrieben:Hallo,

bei der Eingabe einer Zahl mit einem Punkt als Dezimaltrennzeichen (z.B. 34.56) im Editfeld stürzt mein Programm ab.
Im Forum habe ich den DecimalSeperator gefunden und mit der Codezeile:

Code: Alles auswählen

 DecimalSeparator := '.';
kann man jetzt zwar 34.56 eingeben, dafür stürzt das Programm bei 34,56 ab.

Gibt es eine Möglichkeit, dass das Programm bei keiner Variante abstürzt, also weder bei einer Kommazahl noch bei einer durch Punkt getrennten Zahl?
Wichtig: Ich will nur den Absturz verhindern, es soll bei 34.56 eine Fehlermeldung zeigen und bei 34,56 einfach normal rechnen. Es muss also nicht beide Varianten rechnen können.
Die Frage war nach einer Variante, bei der das Programm nicht abstürzt. Und da solche Fehlermeldungen definitiv unnötig sind, da das Dezimalformat dem Benutzer ohnehin klar ist, schränkt man zugunsten der Usability direkt die Eingabe ein und erspart sich die (für den Bneutzer unnötige) Fehlermeldung. Dies mal TFloatSpinEdit, denn genau dafür wurde der Entwickelt. Den Rest könnt ihr nun verdrehen, durchdiskutieren und Spaghetti-Code-posten, wie ihr mögt. Fehlerfrei das, was hier an Code gepostet wurde ohnehin nicht, deshlab kann man sich das sparen.
Grüße, Antrepolit

care only if your os is really burning

kromer
Beiträge: 3
Registriert: Do 14. Aug 2014, 13:00

Re: Im Editfeld eingabe: 34.56 -> absturz

Beitrag von kromer »

theo hat geschrieben:Dieser Thread driftet komplett ab.
Hab schon gar keine Lust mehr, zu den einzelnen Quatschbeiträgen Stellung zu nehmen.
Der letzte Beitrag von TE kromer war jedenfalls vorgestern um 14:21. :shock:
Stimmt, hab vergessen das Thema auf gelöst zu setzen... ;)

Antworten