Prüfen, ob ein String einen Interger darstellt.

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Mathias
Beiträge: 6165
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Prüfen, ob ein String einen Interger darstellt.

Beitrag von Mathias »

Ich habe dies so gelöst:

Code: Alles auswählen

  function IsNumber(s: string): boolean;
  var
    i, er: integer;
  begin
    Val(s, i, er);
    Result := er = 0;
  end;   

Gibt es da schon etwas fertiges ?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
Ally
Beiträge: 263
Registriert: Do 11. Jun 2009, 09:25
OS, Lazarus, FPC: Win und Lazarus Stable release
CPU-Target: x64

Re: Prüfen, ob ein String einen Interger darstellt.

Beitrag von Ally »

Hallo Mathias,

schau dir mal TryStrToInt an, das könnte sein was du suchst.

Gruß Roland

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

Re: Prüfen, ob ein String einen Interger darstellt.

Beitrag von Mathias »

Danke, hat mir weiter geholfen. Spart wieder ein paar Zeilen. :wink:

Code: Alles auswählen

  if TryStrToInt(StringGrid1.Cells[ACol, ARow], i0) and TryStrToInt(StringGrid1.Cells[BCol, BRow], i1) then begin
    Result := i0 - i1;
  end else begin
    Result := CompareStr(StringGrid1.Cells[ACol, ARow], StringGrid1.Cells[BCol, BRow]);
  end;


Intern arbeitet TryStrToInt auch mit val.

Code: Alles auswählen

function TryStrToInt(const s: string; out i : Longint) : boolean;
var Error : word;
begin
  Val(s, i, Error);
  TryStrToInt:=Error=0
end;   
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
Winni
Beiträge: 1577
Registriert: Mo 2. Mär 2009, 16:45
OS, Lazarus, FPC: Laz2.2.2, fpc 3.2.2
CPU-Target: 64Bit
Wohnort: Fast Dänemark

Re: Prüfen, ob ein String einen Interger darstellt.

Beitrag von Winni »

Hi!

Oder ganz einfach selbst machen:

Code: Alles auswählen

 
function IsInteger(s: string) : boolean;
const digits = ['0'..'9'];
var i : integer = 1;
begin
result := true;
while result and (i<= length(s) ) do
  begin
  result := s[i] in digits;
  if result then inc(i);
  end; // while 
end;


Grüße, Winni

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

Re: Prüfen, ob ein String einen Interger darstellt.

Beitrag von Mathias »

Bringt dies bei einem PC etwas ?
Wird val und str nicht von der CPU unterstützt ?
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: Prüfen, ob ein String einen Interger darstellt.

Beitrag von Warf »

Winni hat geschrieben:Hi!

Oder ganz einfach selbst machen:

Code: Alles auswählen

 function IsInteger(s: string) : boolean;
const digits = ['0'..'9'];
var i : integer = 1;
begin
result := true;
while result and (i<= length(s) ) do
  begin
  result := s[i] in digits;
  if result then inc(i);
  end; // while
end;


Grüße, Winni


Warum am ende der branch? Der verhindert das genau einmal ein unnötiges INC ausgeführt wird, die schnellste instruction die eine CPU kann, um statdessen bei jedem anderen mal einen branch und eine instruction auszuführen. Also in jedem Fall in dem nicht direkt das erste zeichen keine Zahl ist, ist es strikt schlechter, (weil ungefähr mehr instructions ausgeführt werden) und in dem Fall ersetzt du einen INC aufruf durch einen branch, was auch nicht schneller ist (vielleicht sogar langsamer)

Außerdem darf man nicht vergessen das const keinen konstanten ausdruck definiert, sondern ein objekt im Data segment des Programms (so wie static in C). Obwohl der Optimizer zwar beweisen können müsste das digits auch als konstanter ausdruck benutzt werden kann, ist das nicht unbedingt garantiert. Der Unterschied ist, wenn es ein Konstanter ausdruck ist kann der Optimizer mehr darüber beweisen, z.b. das das ein zusammenhängendes Set ist, also ein range vergleich (c<min c>max) ausreichend ist. Außerdem kann bei einem Konstanten ausdruck eine Jumping-Table benutzt werden (wie bei einem case-of ausdruck).

Daher mein Vorschlag (vor allem ist er auch kürzer und deutlich leserlicher):

Code: Alles auswählen

function IsInteger(s: string): boolean; inline;
var
  c: char;
begin
  Result := s.length > 0;
  for c in s do
    if not (c in ['0'..'9']) then
      exit(False); // oder Result := False; und break;
end;


An dieser stelle sollte der Optimizer entscheiden was die beste implementierung ist, ansonsten kann man ein case oder ein range if versuchen

Code: Alles auswählen

function IsInteger(s: string): boolean; inline;
var
  c: char;
begin
  Result := s.length > 0;
  for c in s do
    case c of
    '0'..'9':
    else:
      exit(False); // oder Result := False; und break;
    end;
end;

oder:

Code: Alles auswählen

function IsInteger(s: string): boolean; inline;
var
  c: char;
begin
  Result := s.length > 0;
  for c in s do
    if (c < '0') or (c > '9')
      exit(False); // oder Result := False; und break;
end;


Aber das sollte man dem optimizer überlassen, dafür ist er da

Benutzeravatar
six1
Beiträge: 782
Registriert: Do 1. Jul 2010, 19:01

Re: Prüfen, ob ein String einen Interger darstellt.

Beitrag von six1 »

strtointdef wäre auch interessant.
Gruß, Michael

Benutzeravatar
Winni
Beiträge: 1577
Registriert: Mo 2. Mär 2009, 16:45
OS, Lazarus, FPC: Laz2.2.2, fpc 3.2.2
CPU-Target: 64Bit
Wohnort: Fast Dänemark

Re: Prüfen, ob ein String einen Interger darstellt.

Beitrag von Winni »

Hi!

Ja, nicht immer diese langweiligen Konstanten:

BoDieGrosseZersplitterung := StrToIntDef('I Ging',23);

Winni

Benutzeravatar
six1
Beiträge: 782
Registriert: Do 1. Jul 2010, 19:01

Re: Prüfen, ob ein String einen Interger darstellt.

Beitrag von six1 »

ich verwende es in der Art:

Code: Alles auswählen

 
var
  str:string;
begin
  str:='123A';
  if strtointdef( str, -1) = -1 then
   showmessage('Keine Zahl')
  else
   showmessage('Zahl: '+str);
end;
 
Gruß, Michael

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2636
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: Prüfen, ob ein String einen Interger darstellt.

Beitrag von m.fuchs »

six1 hat geschrieben:

Code: Alles auswählen

 
  if strtointdef( str, -1) = -1 then
   showmessage('Keine Zahl')
  else
   showmessage('Zahl: '+str);
 

Was allerdings nicht korrekt ist. So ein Einsatz von magischen Konstanten wie deine -1 ist problematisch. Was machst du wenn wirklich jemand -1 eingibt?
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: Prüfen, ob ein String einen Interger darstellt.

Beitrag von Timm Thaler »

m.fuchs hat geschrieben:Was allerdings nicht korrekt ist. So ein Einsatz von magischen Konstanten wie deine -1 ist problematisch. Was machst du wenn wirklich jemand -1 eingibt?


Dann enthält der Wert -1. ;-)

Normalerweise hat man ja einen gültigen Zahlenbereich, in dem der Wert liegen kann. Und gerade Eingaben sollte man auf diesen prüfen.

So kann man zum Beispiel definieren: cNaN16 = −32768;

Dann kann man dem Wert an Anfang temperatur := cNaN16; zuweisen, und erst wenn ein gültiger Messwert geliefert wird, wird dieser übernommen. Verarbeitet man den Messwert, dann fragt man ab ob temperatur <> cNaN16, nur dann kann man ihn verwenden. Oder Kalibrierwerte die per Uart übermittelt werden können so als gültig markiert werden. Liegen sie außerhalb des Bereiches: cal := cNaN16;

Bei AVR-Controllern, die auch weiterlaufen müssen wenn ein Sensorfehler auftritt und die nicht dem User einfach eine Fehlermeldung auf den Bildschirm klatschen können ist das schon praktisch.

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2636
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: Prüfen, ob ein String einen Interger darstellt.

Beitrag von m.fuchs »

Timm Thaler hat geschrieben:
m.fuchs hat geschrieben:Was allerdings nicht korrekt ist. So ein Einsatz von magischen Konstanten wie deine -1 ist problematisch. Was machst du wenn wirklich jemand -1 eingibt?

Dann enthält der Wert -1. ;-)

Nö, dann behauptet die Software "Keine Zahl". Eine Aussage die falsch ist. Und jeder Benutzer schaut auf den Bildschirm und weiß nicht mehr weiter.

Timm Thaler hat geschrieben:Normalerweise hat man ja einen gültigen Zahlenbereich, in dem der Wert liegen kann. Und gerade Eingaben sollte man auf diesen prüfen.

Vollkommen richtig. Worauf ich hinaus will: die Prüfung muss auch ein korrektes Ergebnis zurückgeben. Wenn die oben genannte Routine sagen würde "Keine positive Zahl" oder "Eingabe außerhalb des gültigen Wertebereichs" wäre ja alles in Ordnung.
Das mag jetzt etwas krümmelkackerich daherkommen, aber genau diese Art von ungenauen Fehlermeldungen führen zu Frustration bei Benutzern.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Benutzeravatar
six1
Beiträge: 782
Registriert: Do 1. Jul 2010, 19:01

Re: Prüfen, ob ein String einen Interger darstellt.

Beitrag von six1 »

ja... man findet immer irgend etwas. Dann passt dieses Beispiel euren Gegebenheiten an.
Gruß, Michael

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

Re: Prüfen, ob ein String einen Interger darstellt.

Beitrag von wp_xyz »

Na dann viel Spaß beim Fehlersuchen in einem Jahr, wenn du all das hier vergessen hast und dich plötzlich wunderst, warum deine User dir empört melden, dein Programm würde die Eingabe -1 als "keine Zahl" bemängeln.

Benutzeravatar
six1
Beiträge: 782
Registriert: Do 1. Jul 2010, 19:01

Re: Prüfen, ob ein String einen Interger darstellt.

Beitrag von six1 »

wp_xyz hat geschrieben:Na dann viel Spaß beim Fehlersuchen in einem Jahr, wenn du all das hier vergessen hast und dich plötzlich wunderst, warum deine User dir empört melden, dein Programm würde die Eingabe -1 als "keine Zahl" bemängeln.


ja, superschlauer Einwand :roll:
Woher kennst du Interna meiner Programme?
Wenn es im jeweiligen Programm nicht passt strtointdef zu verwenden, würde ich es einfach nicht verwenden; schon mal drüber nachgedacht?

Diese Schlaumeierei ist manchmal echt schwer zu ertragen. Ein Hinweis auf mögliche Komplikationen hätte auch ausgereicht und das Problem verständlich gemacht.
Gruß, Michael

Antworten