AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Alternative zu PosEx

Ein Thema von Amateurprofi · begonnen am 19. Nov 2024 · letzter Beitrag vom 4. Dez 2024
Antwort Antwort
Blup

Registriert seit: 7. Aug 2008
Ort: Brandenburg
1.487 Beiträge
 
Delphi 12 Athens
 
#1

AW: Alternative zu PosEx

  Alt 26. Nov 2024, 15:53
Ich habe StrPosEx (32Bit) getestet und einen Fehler gefunden:
Code:
SetLength(Positions, 3)
StrPosEx('PaPa', 'PaPaPa', Positions)
Result = 1
Positions = [1,0,0]
Man muss das Array vor dem Aufruf auf die Anzahl der Ergebnisse anpassen.
Wenn der Platz nicht reicht, liefert die Funktion aber nicht die tatsächliche Anzahl zurück.
Die Fehlercodes sind für eine so simple Funktion eigentlich überflüssig, entweder es wird gefunden oder nicht.
Simple Überprüfungen kann man davor selbst vornehmen.

Meiner Meinung nach sollte die Funtktion den benötigten Platz selbst reservieren, z.B.:
Delphi-Quellcode:
function StrPosEx(const SearchFor, SearchIn: string; out Positions: TIntegerDynArray): Integer;
function StrPosEx(const SearchFor, SearchIn: string): TIntegerDynArray;

Geändert von Blup (26. Nov 2024 um 15:56 Uhr)
  Mit Zitat antworten Zitat
Amateurprofi

Registriert seit: 17. Nov 2005
Ort: Hamburg
1.100 Beiträge
 
Delphi XE2 Professional
 
#2

AW: Alternative zu PosEx

  Alt 26. Nov 2024, 16:45
Ich habe StrPosEx (32Bit) getestet und einen Fehler gefunden:
Code:
SetLength(Positions, 3)
StrPosEx('PaPa', 'PaPaPa', Positions)
Result = 1
Positions = [1,0,0]
Man muss das Array vor dem Aufruf auf die Anzahl der Ergebnisse anpassen.
Wenn der Platz nicht reicht, liefert die Funktion aber nicht die tatsächliche Anzahl zurück.
Die Fehlercodes sind für eine so simple Funktion eigentlich überflüssig, entweder es wird gefunden oder nicht.
Simple Überprüfungen kann man davor selbst vornehmen.

Meiner Meinung nach sollte die Funtktion den benötigten Platz selbst reservieren, z.B.:
Delphi-Quellcode:
function StrPosEx(const SearchFor, SearchIn: string; out Positions: TIntegerDynArray): Integer;
function StrPosEx(const SearchFor, SearchIn: string): TIntegerDynArray;
Und wo ist da der Fehler?
"PaPa" wird in "PaPaPa" an Position 1 gefunden.
Dann wird geprüft, ob ab hinter der Fundstelle, also ab Position 1+Length("PaPa") der Text "PaPa" noch einmal gefunden wird.
Das ist nicht der Fall, also wird korrekt 1 zurückgegeben.

Zu "Meiner Meinung nach sollte die Funtktion den benötigten Platz selbst reservieren".
Hast Du einen Vorschlag, wie das zu realisieren ist?
Gruß, Klaus
Die Titanic wurde von Profis gebaut,
die Arche Noah von einem Amateur.
... Und dieser Beitrag vom Amateurprofi....
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.385 Beiträge
 
Delphi 12 Athens
 
#3

AW: Alternative zu PosEx

  Alt 26. Nov 2024, 16:50
Zitat:
wie
Als VAR-Parameter und drinnen ein SetLength.


Per se ist OUT hier falsch, jedenfalls in Bezug auf Managed-Types, wie z.B. dynamische Arrays.
Zum Glück macht Delphi hier heimlich, und ohne was zu sagen, ein VAR daraus.

Bei OUT ist es möglich auch die Referenz zu ändern, was hier "eigentlich" zu einem Speicherleck führen würde, wenn vor dem Aufruf das Array einen Inhalt hätte.
Ein Therapeut entspricht 1024 Gigapeut.
  Mit Zitat antworten Zitat
Amateurprofi

Registriert seit: 17. Nov 2005
Ort: Hamburg
1.100 Beiträge
 
Delphi XE2 Professional
 
#4

AW: Alternative zu PosEx

  Alt 26. Nov 2024, 22:01
Zitat:
wie
Als VAR-Parameter und drinnen ein SetLength.


Per se ist OUT hier falsch, jedenfalls in Bezug auf Managed-Types, wie z.B. dynamische Arrays.
Zum Glück macht Delphi hier heimlich, und ohne was zu sagen, ein VAR daraus.

Bei OUT ist es möglich auch die Referenz zu ändern, was hier "eigentlich" zu einem Speicherleck führen würde, wenn vor dem Aufruf das Array einen Inhalt hätte.
Hast Du auch einen Vorschlag wie man das in einer Assembler-Routine realisieren kann (32BitAsm und 64BitAsm)?
Ich hatte das vor langer Zeit mal versucht.
Weiß nicht mehr woran es scheiterte, hab aber die unangenehme Erinnerung, dass ich es nicht hingekriegt habe, was aber nicht wirklich der Grund für meine Vorgehensweise war.
Ich hab die Funktion ja im Zusammenhang mit Mersenne-Primzahlen und den daraus abgeleiteten Perfekten Zahlen geschrieben.
Die zZ längste Zahl "(2^136279841-1) * 2^(136279841-1)" hat 82,048,640 Ziffern.
Rein theoretisch müsste ich, um auf der sicheren Seite zu liegen, das Array auf eine Länge von 82,048,640 setzen = 330MB.
Es ist aber so, dass mein Programm, dann wenn eine Zahl geladen wird, zählt, welche Ziffer wie oft vorkommt.
Am häufigsten, bei der og Zahl die 7 (8,202,366 Mal).
Also muss ich das Array "nur" auf eine Länge von 8,202,366 setzen = 33MB.
In einer allgemeingültigen Funktion ist eine Abschätzung, wie lang das Array sein muss eher nicht möglich.
Wenn ich wiederholte Längenänderungen vermeiden will müsste ich also für eine Suche nach einzelnen Zeichen die Länge auf die Länge des zu durchsuchenden Strings setzen, ZZ 330MB, bei den nächsten Mersenne-Primzahlen sicherlich > 1GB, und dann wird es problematisch.
Unabhängig davon wüsste ich aber gern, wie man ein SetLength in Assembler realisieren kann.
Gruß, Klaus
Die Titanic wurde von Profis gebaut,
die Arche Noah von einem Amateur.
... Und dieser Beitrag vom Amateurprofi....
  Mit Zitat antworten Zitat
Blup

Registriert seit: 7. Aug 2008
Ort: Brandenburg
1.487 Beiträge
 
Delphi 12 Athens
 
#5

AW: Alternative zu PosEx

  Alt 28. Nov 2024, 09:22
Per se ist OUT hier falsch, jedenfalls in Bezug auf Managed-Types, wie z.B. dynamische Arrays.
Zum Glück macht Delphi hier heimlich, und ohne was zu sagen, ein VAR daraus.

Bei OUT ist es möglich auch die Referenz zu ändern, was hier "eigentlich" zu einem Speicherleck führen würde, wenn vor dem Aufruf das Array einen Inhalt hätte.
Da Managed-Types immer initialisisert sind, wäre OUT nach deiner Auffassung für diese immer falsch.
OUT intern für Managed-Types als VAR zu behandeln macht Delphi schon richtig, beide übergeben einen Zeiger auf die Variable.

Was meiner Meinung nach fehlt ist eine Warnung auch für Managed-Types.
- VAR-Parameter: Warnung wenn vorher keine Zuweisung auf die Variable erfolgt (kann auch leer sein, aber automatische Initialisierung zählt nicht)
- OUT-Parameter: Warnung wenn vorher eine Zuweisung auf die Variable erfolgt, diese Variable aber nicht mehr vor dem Aufruf als OUT-Parameter ausgewertet wird.
  Mit Zitat antworten Zitat
Maekkelrajter

Registriert seit: 8. Mär 2017
Ort: Köln
157 Beiträge
 
Delphi 12 Athens
 
#6

AW: Alternative zu PosEx

  Alt 28. Nov 2024, 10:20
Ich habe auch schon die Erfahrung gemacht das FPC/Delphi schnelleren Code erzeugt hat als selbst geschriebener Assembler.
Das ging mir ähnlich. Aus 'maschinen-nahem' Pascal mit Delphi 4 compilierter Code war schneller als meine selbstgeschiebenen Assembler-Routinen, die unter TP6 bzw. BP7 noch für einen ordentlichen Performance-Schub gesorgt hatten.

Einzig dein neuer 4. Parameter, um den Suchbereich zu limitieren, ist interessant und ggf eine Überlegung wert, diesen in der RTL auch unterzubringen.
Sollte sogar ziemlich einfach zu implementieren sein, da dieser der Länge des zu durchsuchenden Strings entspricht, die intern sowieso ermittelt wird.
Hier hatte ich mich vor ein paar Jahren schon mit dem Thema befasst und eine Variante von Pos() mit 4 Parametern entwickelt.

Gruß LP
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.045 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#7

AW: Alternative zu PosEx

  Alt 28. Nov 2024, 10:42
Ich hab mir mal System._UStrPos in Delphi 12 angeschaut und wenn ich nicht komplett auf dem Holzweg bin, dann ist die Erweiterung mit einigen wenigen Anpassungen erledigt. Defaultwert von Count ist MaxInt

Hier mal der relevante Ausschnitt
Delphi-Quellcode:
begin
- if (Str = nil) or (SubStr = nil) or (Offset < 1) then
+ if (Str = nil) or (SubStr = nil) or (Offset < 1) or (Count < 1) then
    goto Exit0;

  // fast access to length - did the nil check already
  lenSub := PInteger(SubStr)[-1];
  Dec(lenSub);
  len := PInteger(Str)[-1];
+ Dec(Offset);
+ Cardinal(Count) := Cardinal(Count) + Cardinal(Offset);
+ if Cardinal(len) > Cardinal(Count) then len := Count;
- if (len < lenSub + Offset) then
+ if (len <= lenSub + Offset) then
    goto Exit0;

  Stop := @Str[len];
  Str := @Str[lenSub];
  SubStr := @SubStr[lenSub];
  Start := Str;
- Str := @Str[Offset + 3];
+ Str := @Str[Offset + 4];
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight
  Mit Zitat antworten Zitat
Blup

Registriert seit: 7. Aug 2008
Ort: Brandenburg
1.487 Beiträge
 
Delphi 12 Athens
 
#8

AW: Alternative zu PosEx

  Alt 28. Nov 2024, 15:02
Zum Vergleich mit Pos() und SetLength() für das Ergebnis:
Delphi-Quellcode:
function MyStrPosEx(const SearchFor, SearchIn: string): TIntegerDynArray;

  function Search(var Index: Integer): Boolean;
  begin
    Index := Pos(SearchFor, SearchIn, Index + 1);
    Result := (Index > 0);
  end;

begin
  var Count: Integer := 0;
  var Index: Integer := 0;
  while Search(Index) do
  begin
    Inc(Count);
    {Array vergrößern braucht viel Zeit, deshalb gleich etwas mehr Platz reservieren}
    if Length(Result) < Count then
      SetLength(Result, Count * 4);

    Result[Count - 1] := Index;
  end;
  SetLength(Result, Count);
end;
Code:
sRandomString := RandomString(MaxInt div 8 - 6) + 'PaPaPa'
0:00:01.327

SetLength(Positions, 3)
StrPosEx('PaPa', 'sRandomString', Positions)
0:00:00.081
Result = 1
Positions = [268435450,0,0]

Result := MyStrPosEx('PaPa', 'sRandomString')
0:00:00.075
Result = [268435450,268435452]
  Mit Zitat antworten Zitat
Blup

Registriert seit: 7. Aug 2008
Ort: Brandenburg
1.487 Beiträge
 
Delphi 12 Athens
 
#9

AW: Alternative zu PosEx

  Alt 28. Nov 2024, 09:04
Und wo ist da der Fehler?
"PaPa" wird in "PaPaPa" an Position 1 gefunden.
Dann wird geprüft, ob ab hinter der Fundstelle, also ab Position 1+Length("PaPa") der Text "PaPa" noch einmal gefunden wird.
Das ist nicht der Fall, also wird korrekt 1 zurückgegeben.
Das ist Ansichtssache. Bei einer Funktion die Sucht und Ersetzt wäre dies auch sicherlich richtig.
Bei einer Funktion die alle Fundstellen zurückgibt, erwarte ich alle, auch wenn die gefundenen Zeichenketten sich überschneiden.
Welche davon ignoriert werden, kann man beim Verarbeiten des Ergebnis der Suche entscheiden.
  Mit Zitat antworten Zitat
Amateurprofi

Registriert seit: 17. Nov 2005
Ort: Hamburg
1.100 Beiträge
 
Delphi XE2 Professional
 
#10

AW: Alternative zu PosEx

  Alt 29. Nov 2024, 00:40
Und wo ist da der Fehler?
"PaPa" wird in "PaPaPa" an Position 1 gefunden.
Dann wird geprüft, ob ab hinter der Fundstelle, also ab Position 1+Length("PaPa") der Text "PaPa" noch einmal gefunden wird.
Das ist nicht der Fall, also wird korrekt 1 zurückgegeben.
Das ist Ansichtssache. Bei einer Funktion die Sucht und Ersetzt wäre dies auch sicherlich richtig.
Bei einer Funktion die alle Fundstellen zurückgibt, erwarte ich alle, auch wenn die gefundenen Zeichenketten sich überschneiden.
Welche davon ignoriert werden, kann man beim Verarbeiten des Ergebnis der Suche entscheiden.
Zu "Bei einer Funktion die Sucht und Ersetzt wäre dies auch sicherlich richtig."
Ja, und meine Ansicht ist, dass eine Suche genau die Fundstellen finden soll, die im Zweifelsfall auch ersetzt würden.

Aber, wie du sagtest: Ist Ansichtssache.
Ich bin zum Beispiel der Ansicht, dass 2 * 2 = 5 ergeben sollte, wenn in 2024 der 31te eines Monats auf einen Montag fällt.
Gruß, Klaus
Die Titanic wurde von Profis gebaut,
die Arche Noah von einem Amateur.
... Und dieser Beitrag vom Amateurprofi....
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 15:26 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz