Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   POS findet was das ich nicht verstehe... ? (https://www.delphipraxis.net/179721-pos-findet-das-ich-nicht-verstehe.html)

user0815 27. Mär 2014 11:04

Delphi-Version: XE2

POS findet was das ich nicht verstehe... ?
 
Warum ?

Delphi-Quellcode:
  private
    { Private-Deklarationen }
    Nachrichtentext : String;

    procedure GetParameter(var Value : String; Suche : String);
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}


procedure TForm1.GetParameter(var Value : String; Suche : String);
var
  i, j : Integer;
  s : String;
begin
  s := '';

  j := POS(Suche, Nachrichtentext) + length(Suche);

  for i := j to length(Nachrichtentext) do
    if Nachrichtentext[i] <> ';'
     then s := s + Nachrichtentext[i]
      else break;

  Value := s;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
 s1, s2, s3 : String;
begin
  Nachrichtentext := 'S;XY41380993;P=10000,1;M1=012324016940;M2=;F-18;';

  GetParameter(s1,';M1=');
  GetParameter(s2,';M2=');
  GetParameter(s3,';W=');

  Memo1.Lines.Append(s1);
  Memo1.Lines.Append(s2);
  Memo1.Lines.Append(s3);
end;
Als Ausgabe im Memo1 erhalte ich:
Code:
012324016940

XY41380993
:?: XY41380993 dürfte nicht ausgegeben werden ?

Grüße
0815

Klaus01 27. Mär 2014 11:12

AW: POS findet was das ich nicht verstehe... ?
 
Hallo,

du setzt j auf einen Wert, unabhänging davon ob mit pos der SubString gefunden wurde.

-1 +3 = 2 -> XY41380993

Grüße
Klaus

user0815 27. Mär 2014 11:16

AW: POS findet was das ich nicht verstehe... ?
 
Ahhhh, manchmal hat man echt ein Brett vor´m Kopf.
Danke !

Perlsau 27. Mär 2014 11:52

AW: POS findet was das ich nicht verstehe... ?
 
Weshalb so umständlich?
Delphi-Quellcode:
function GetValue(Suche : String) : String;
Var
  p : Integer;
  S : String;

begin
  Result := '';
  S := Nachrichtentext;

  p := Pos(Suche, S); // nach dem Suchstring suchen
  if p = 0 then exit; // wenn nichts gefunden, dann raus

  // wenn gefunden, dann ...
  Delete(S, 1 ,p + Length(S)-1); // ab gefundener Position die Länge des Suchstrings löschen

  p := Pos(';', S); // nach Delimiter suchen
  if p = 0 then exit; // wenn nichts gefunden, dann raus

  // wenn gefunden, dann Result zuweisen
  Result := Copy(S, 1, p-1);
end;

Popov 27. Mär 2014 12:08

AW: POS findet was das ich nicht verstehe... ?
 
Wie wäre sowas:
Delphi-Quellcode:
procedure GetParameter2(Nachrichtentext: String; var Value : String; Suche : String);
begin
  with TStringList.Create do
  try
    Delimiter := ';';
    DelimitedText := Nachrichtentext;
    Value := Values[Suche];
  finally
    Free;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
 s1, s2, s3 : String;
 Nachrichtentext: String;
begin
  Nachrichtentext := 'S;XY41380993;P=10000,1;M1=012324016940;M2=;F-18;';

  GetParameter2(Nachrichtentext, s1, 'M1');
  GetParameter2(Nachrichtentext, s2, 'M2');
  GetParameter2(Nachrichtentext, s3, 'W');

  Memo1.Lines.Append(s1);
  Memo1.Lines.Append(s2);
  Memo1.Lines.Append(s3);
end;
Etwas OOP lastig, aber es funktioniert.

user0815 27. Mär 2014 12:26

AW: POS findet was das ich nicht verstehe... ?
 
obiges war nur verkürzter Beispielcode.

Zitat:

Delphi-Quellcode:
  p := Pos(Suche, S); // nach dem Suchstring suchen
  if p = 0 then exit; // wenn nichts gefunden, dann raus

das habe ich jetzt ähnlich drinnen. Die echte Procedure sucht auch Rückwärts, usw...
Nochmal Danke, das Thema hat sich erledigt.

himitsu 27. Mär 2014 12:57

AW: POS findet was das ich nicht verstehe... ?
 
Zitat:

Zitat von Perlsau (Beitrag 1253625)
Weshalb so umständlich?

Wobei ein Delete auch nicht immer so gut ist, bei all den entstehenden und "unnötigen" Speicheroperationen.
Via PosEx lässt sich das auch Ohne problemlos lösen.

Popov 27. Mär 2014 13:09

AW: POS findet was das ich nicht verstehe... ?
 
Jep. PosEx habe ich auch all zu lange ignoriert (vielleicht weil man einzig wegen der Funktion die sonst kaum genutzte Unit StrUtils einbinden muss). Auf jeden Fall kann man damit einen ganzen String ohne Delete zerlegen. Auf der anderen Seite stellt sich die Frage was optimaler ist, eine extra Unit oder mit Delete arbeiten.

himitsu 27. Mär 2014 13:18

AW: POS findet was das ich nicht verstehe... ?
 
Die StrUtils ist bei mir eh oftmals mit drin, da die noch andere nette Funktionen drin hat. :angel:
StartsText, ContainsText, EndsText, MatchText, IndexText (auch gut für ein CASE mit Strings) uvvm.

In Math liegen zwar ein paar IfThen, aber die String-Version versteckt sich in der StrUtils.


PS: Die StrUtils selber vergrößert die EXE selber praktisch garnicht.
- ungenutzte Funktionen werden nicht in die Anwendung gelinkt
- es gibt keinen "initialization"-Abschnitt oder globale Variablen
- bis auf die SysUtils werden keine bösen Units eingebunden

Popov 27. Mär 2014 14:13

AW: POS findet was das ich nicht verstehe... ?
 
Hm, vielleicht sollte ich mir die Unit mal genauer angucken. Was ich bisher gesehen habe erinnert mich leicht an meinen alten TI-99/4A. Der hatte auch viele tolle String-Funktionen, die ich später beim C64 vermisst habe und nun hier wieder entdecke ;)

v2afrank 28. Mär 2014 09:49

AW: POS findet was das ich nicht verstehe... ?
 
Und ich habe gelernt dass man nicht jede Delphi Funktion bei Google eingeben kann. Da ich PosEX auch noch nie benutzt habe, habe ich da mal bei Google nach gesucht.(Allerdings ohne das Schlagwort Delphi). Hat mit Programmierung nicht mehr viel zu tun

himitsu 28. Mär 2014 10:01

AW: POS findet was das ich nicht verstehe... ?
 
:lol:

Gib es mal da ein. :zwinker:
http://www.delphipraxis.net/dp_reference.php

sx2008 28. Mär 2014 12:11

AW: POS findet was das ich nicht verstehe... ?
 
Also ganz allgemein sollte man Funktionen gegenüber Prozeduren mit einem Var-Parameter bevorzugen.
Perlsau hat das im Beitrag #4 schon ganz richtig gemacht. (man sollte aber auch den "Nachrichtentext" als weiteren Parameter übergeben)

Insbesondere Funktionen die ausschlieslich von ihren Eingangsparameter(n) abhängen und keine Nebeneffekte haben (sog. pure functions) machen das Testen des Codes zum Kinderspiel.

Sir Rufo 28. Mär 2014 12:51

AW: POS findet was das ich nicht verstehe... ?
 
Die richtige Implementierung wäre:
Delphi-Quellcode:
function GetParamValue( const AText, AParamName : string; out Value : string ) : Boolean;
begin
  ...
end;
und der Aufruf
Delphi-Quellcode:
var
  Nachricht : string;
  S1, S2 : string;

GetParamValue( Nachricht, 'M1', S1 );

if not GetParamValue( Nachricht, 'M2', S2 ) then
  raise Exception.Create( 'Parameter M2 wird zwingend benötigt!' );
Documentation by Design
  • Alle benötigten Informationen werden übergeben (keine magischen Daten von irgendwo)
  • Delphi-Quellcode:
    AText
    und
    Delphi-Quellcode:
    AParamName
    werden durch den Aufruf nicht verändert
    Delphi-Quellcode:
    const
  • Delphi-Quellcode:
    Value
    wird für die Ermittlung nicht benötigt und gibt nur etwas zurück
    Delphi-Quellcode:
    out
  • Wird ein Wert zwingend benötigt, so muss nicht
    Delphi-Quellcode:
    Value
    überprüft werden, sondern einfach nur der
    Delphi-Quellcode:
    Result
    des Aufrufs (kompakter und lesbarer)

himitsu 28. Mär 2014 12:56

AW: POS findet was das ich nicht verstehe... ?
 
richtig...

Man kann es auch wie bei StrToInt, TryStrToInt und StrToIntDef machen?

Oder ParamStr, was beim Fehlen einen Leerstring liefert.

Sir Rufo 28. Mär 2014 13:01

AW: POS findet was das ich nicht verstehe... ?
 
Zitat:

Zitat von himitsu (Beitrag 1253789)
richtig...

Man kann es auch wie bei StrToInt, TryStrToInt und StrToIntDef machen?

Oder ParamStr, was beim Fehlen einen Leerstring liefert.

Die Basis ist aber immer
Delphi-Quellcode:
TryStrToInt
Delphi-Quellcode:
function TryFoo( const AInput : TSomething; out AOutput : TDifferent ) : Boolean;
begin
  ...
end;

function Foo( const AInput : TSomething ) : TDifferent;
begin
  if not TryFoo( AInput, Result ) then
    raise EFooException.Create( 'Please try something different' );
end;

function FooDefault( const AInput, ADefault : TSomething ) : TDifferent;
begin
  if not TryFoo( AInput, Result ) then
    Result := ADefault;
end;

himitsu 28. Mär 2014 16:19

AW: POS findet was das ich nicht verstehe... ?
 
Zitat:

Zitat von v2afrank (Beitrag 1253763)
Und ich habe gelernt dass man nicht jede Delphi Funktion bei Google eingeben kann. Da ich PosEX auch noch nie benutzt habe, habe ich da mal bei Google nach gesucht.(Allerdings ohne das Schlagwort Delphi). Hat mit Programmierung nicht mehr viel zu tun

Es kommt drauf an ... hatte grade mal versuchsweise das SafeSearch wieder aktiviert, aber dann entgehen einem die Artikel von goFeminin und deren coole musikalische Werbung im Hintergrund.

Garfield 28. Mär 2014 16:24

AW: POS findet was das ich nicht verstehe... ?
 
Zitat:

Zitat von Sir Rufo (Beitrag 1253794)
Die Basis ist aber immer
Delphi-Quellcode:
TryStrToInt

:gruebel: Ich dachte val. Habe das auch genommen, weil es kein StrToUInt gibt.

himitsu 28. Mär 2014 16:43

AW: POS findet was das ich nicht verstehe... ?
 
Wenn du mehr brauchst, dann StrToInt64. (andersrum ist die 64 einfach nur überladen, da dort automatisch entschieden wird, anhand des Parameters)

Garfield 28. Mär 2014 16:50

AW: POS findet was das ich nicht verstehe... ?
 
Könnte ich machen. Aber die Werte in den Strings werden in LowPart und HighPart eines TULargeInteger eingetragen.

Furtbichler 28. Mär 2014 17:15

AW: POS findet was das ich nicht verstehe... ?
 
Zitat:

Zitat von Sir Rufo (Beitrag 1253787)
Die richtige Implementierung wäre...

Ich wusste nicht, das es richtig ist, wenn eine Funktion zwei Werte liefert: Einen 'Value' und einen Rückgabewert. Zudem wäre eine Erklärung, wie Du sie angibst, ja überflüssig, wenn der Code wirklich selbstdokumentierend wäre ;-)
Wie wäre es (beim Ansatz 'self documenting code') mit drei Funktionen?
Delphi-Quellcode:
Function HasParameter (const AText, AParamName : string) : Boolean;
Function GetOptionalParamValue (const AText, AParamName : string) : String;
Function GetMandantoryParamValue (const AText, AParamName : string) : String;
DAS wäre dann selbstdokumentierend. Finde ich.

Sir Rufo 28. Mär 2014 17:17

AW: POS findet was das ich nicht verstehe... ?
 
Zitat:

Zitat von Garfield (Beitrag 1253838)
Zitat:

Zitat von Sir Rufo (Beitrag 1253794)
Die Basis ist aber immer
Delphi-Quellcode:
TryStrToInt

:gruebel: Ich dachte val. Habe das auch genommen, weil es kein StrToUInt gibt.

Jupp, da wird als Basis die System-Funktion Delphi-Referenz durchsuchenSystem.Val benutzt.
Der Code-Wert wird aber dort nur auf
Delphi-Quellcode:
= 0
oder
Delphi-Quellcode:
<> 0
ausgewertet, so dass man diese Teile auch problemlos so hätte deklarieren können:
Delphi-Quellcode:
function TryStrToInt( const S: string; out Value: Integer ) : Boolean;
var
  E: Integer;
begin
  Val(S, Value, E);
  Result := E = 0;
end;

function StrToInt(const S: string): Integer;
begin
  if not TryStrToInt(S, Result) then ConvertErrorFmt(@System.SysConst.SInvalidInteger, [S]);
end;

function StrToIntDef(const S: string; Default: Integer): Integer;
begin
  if not TryStrToInt(S, Result) then Result := Default;
end;

Garfield 28. Mär 2014 17:20

AW: POS findet was das ich nicht verstehe... ?
 
Gut. Damit verstehe ich Dich.

Sir Rufo 28. Mär 2014 17:22

AW: POS findet was das ich nicht verstehe... ?
 
Zitat:

Zitat von Furtbichler (Beitrag 1253844)
Zitat:

Zitat von Sir Rufo (Beitrag 1253787)
Die richtige Implementierung wäre...

Ich wusste nicht, das es richtig ist, wenn eine Funktion zwei Werte liefert: Einen 'Value' und einen Rückgabewert. Zudem wäre eine Erklärung, wie Du sie angibst, ja überflüssig, wenn der Code wirklich selbstdokumentierend wäre ;-)
Wie wäre es (beim Ansatz 'self documenting code') mit drei Funktionen?
Delphi-Quellcode:
Function HasParameter (const AText, AParamName : string) : Boolean;
Function GetOptionalParamValue (const AText, AParamName : string) : String;
Function GetMandantoryParamValue (const AText, AParamName : string) : String;
DAS wäre dann selbstdokumentierend. Finde ich.

Wenn du das so machst, dann bin ich direkt bei dir:
Delphi-Quellcode:
Function HasParameter (const AText, AParamName : string) : Boolean;
Function GetOptionalParamValue (const AText, AParamName, ADefault : string) : String; // ADefault fehlte
Function GetMandantoryParamValue (const AText, AParamName : string) : String;
und als Basis für alle kann man dann diese Funktion nutzen
Delphi-Quellcode:
function TryGetParamValue(const AText, AParamName : string; out Value : string ) : Boolean;
begin
  ...
end;

Furtbichler 28. Mär 2014 18:36

AW: POS findet was das ich nicht verstehe... ?
 
Warte mal, dann braucht man doch nur zwei Funktionen: 'HasParameter' und 'GetParameter'. Fertig. 'GetParameter' wirft eine Exception, wenn der Parameter nicht zu finden ist und das Defaultzeugs kann man sich zusammenbauen:
Delphi-Quellcode:
Function GetOptionalParameter (const aText, aParam, aDefault : String) : String;
Begin
  if HasParameter (aParam, aText) then
    result := GetParameter (aText, aParam)
  else
    result := aDefault;
End;
So isses chön, ne?

Sir Rufo 28. Mär 2014 18:58

AW: POS findet was das ich nicht verstehe... ?
 
Zitat:

Zitat von Furtbichler (Beitrag 1253858)
Warte mal, dann braucht man doch nur zwei Funktionen: 'HasParameter' und 'GetParameter'. Fertig. 'GetParameter' wirft eine Exception, wenn der Parameter nicht zu finden ist und das Defaultzeugs kann man sich zusammenbauen:
Delphi-Quellcode:
Function GetOptionalParameter (const aText, aParam, aDefault : String) : String;
Begin
  if HasParameter (aParam, aText) then
    result := GetParameter (aText, aParam)
  else
    result := aDefault;
End;
So isses chön, ne?

Dann implementiere diese beiden Methoden doch mal DRY und du kommst wieder bei
Delphi-Quellcode:
TryGetParamValue
raus :mrgreen:

Furtbichler 28. Mär 2014 19:09

AW: POS findet was das ich nicht verstehe... ?
 
Darum geht es nicht. Ich kann auch alles in eine Methode packen, die hochredundant ist, alles in einem Abwasch durchläuft und spuperduperperformant ist. Leider widersprechen sich Lesbarkeit und Performance häufig.

'Richtig' implementiert ist auch so eine Sache: Entweder gehe ich auf Lesbarkeit, Clean Code o.ä, oder eben auf 'richtig flott'. Hier dachte ich, es geht um Lesbarkeit, Das man in der konkreten Implementierung u.U. eine Codezeile doppelt ausführt, ist dann eben so und kein Verstoß gegen DRY. By DRY geht es ja um die Vermydung von Codeblockduplikaten, nicht von einfachen Aufrufen.
Delphi-Quellcode:
Function HasParameter (aText, aParam : String) : Boolean;
Begin
  Result := ParameterIndex (aText, aParam) > 0;
End;

Function GetParamValue(aText, aParam : String) : Boolean;
Begin
  i := ParameterIndex(aText, aParam);
  if i=0 then Raise Exception.Create('Parameter gibbet nich');
  Result := ReadValueStartingAtPos(aText, i);
End;
Na, issok?

Sir Rufo 28. Mär 2014 19:28

AW: POS findet was das ich nicht verstehe... ?
 
Nun ja,

um den ParameterIndex zu ermitteln, muss der Text durch einen "Parser" (wo fängt der Wert zum Parameter an).
Um den ParameterWert zu ermitteln, muss der Text wieder durch einen "Parser" (wo hört der Wert zum Parameter auf).

Da das nicht nur sehr ähnlich ist (des Einen Ende ist des Anderen Anfang) würde ich das in einer Funktion implementieren.

Dann ist es der sogenannte DRY KISS ;)

Furtbichler 28. Mär 2014 19:48

AW: POS findet was das ich nicht verstehe... ?
 
Zitat:

Zitat von Sir Rufo (Beitrag 1253865)
Nun ja...Dann ist es der sogenannte DRY KISS ;)

So so, wenn Du das so implementieren willst, bitte sehr.

Hier wird genau einmal geparst.
Delphi-Quellcode:
Function ParameterIndex (aText, aParam : String) : Integer;
Begin
  if ParamDictionary.Contains(aParam) then
    result := ParamDictionary[aParam]
  else begin
    result := FindParam(aText,aParam);
    ParamDictionary.Add(aParam, Result);
  end
end;
PS: Was ist eigentlich das Gegenteil von DRY KISS? Der WET FART? :stupid:

Im Ernst: DRY ist ja ganz nett als Programmierparadigma. Aber wenn ich dann schlechter lesbaren Code produziere, dann muss ich mich entscheiden. Ich persönlich kann mit diesen kombinierten Sachen nichts anfangen. Und über den besten Code kann man vortrefflich streiten (oder ein Bier aufmachen).

Es kommt auf die Implementierung an. Wichtig ist, das ich vorne ein einfaches und minimales Interface habe. Was ich damit anstelle ('TryGet' etc.) ist dann etwas anderes.

Edit: Und natürlich ist der Ansatz, das ganze einmal zu parsen ('TryParse'), im Sinne von DRY optimal. Aber DRY ist nicht alles. Es gibt auch noch den 'Clean Code' Ansatz (dessen eine Facette DRY ist). Beides komplett unter einen Hut zu bekommen, ist manchmal nicht so leicht.

Letztendlich würde man hier den Parameter in den Vordergrund stellen, eine entsprechend Klasse entwicklen, die sich aus dem Text einmalig die Position ermittelt. Und dann diesem Parameter die hier vorgestellten Methoden 'Exists' (aka 'HasParameter') und 'Value' spendieren. Hier haben wir ja aus einer einfachen Idee ('Richtig machen') auf prozeduraler Ebene versucht, moderne Konzepte anzuwenden. Das geht nicht ohne Weiteres.


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:59 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz