![]() |
PosExUltra - Ultimative Stringsuche/Parser
Wenn ihr schon immer mal eine Funktion gebraucht habt, die euch Webseiten und große Texte parsen/filtern/auslesen kann,
OHNE dass ihr ewig euch mit Pos und PosEx rumärgern müsst, dann hat eure Suche ein Ende! PS: Für Verbesserungen, optimierungen wären wir sehr Dankbar!
Delphi-Quellcode:
Erklärung:
{
* -------------------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" * YaNNiC und Novo schrieben diese Datei. Solange Sie diesen Vermerk nicht entfernen, * können Sie mit der Datei machen, was Sie möchten. Wenn wir uns eines Tages treffen * und Sie denken, die Datei ist es wert, können Sie mir dafür ein Bier ausgeben. * Wir hatten auf jeden Fall genug davon, als wir diese Funktion geschrieben haben :D * -------------------------------------------------------------------------------------- } procedure PosExUltra(source, searchwordbefore, searchwordafter, addbefore, addafter: string; continuesearch, reversesearch: boolean; liste: Tstringlist); var Anfang, Ende, Posi: Integer; Ergebnis: string; begin if reversesearch then begin //if reversesearch = true: if continuesearch then begin //if continuesearch = true: Ende := 0; while PosEx(searchwordafter, source, ende) > 0 do begin Anfang := PosEX(searchwordafter, source, Ende); Posi := Anfang; if Anfang > 0 then begin while (PosEX(searchwordbefore, source, Posi) = 0) or (PosEX(searchwordbefore, source, Posi) > Posi) do begin Dec(Posi); end; Ergebnis := Copy(source, Posi + length(searchwordbefore), Anfang - (Posi + length(searchwordbefore))); if (Ergebnis <> '') or (Ergebnis <> ' ') then liste.Add(addbefore + Ergebnis + addafter); Ende := Posi + length(searchwordbefore) + Length(Ergebnis) + Length(searchwordafter); end; end; end else //if continuesearch = false: begin Ende := 0; Anfang := PosEX(searchwordafter, source, Ende); Posi := Anfang; if Anfang > 0 then begin while (PosEX(searchwordbefore, source, Posi) = 0) or (PosEX(searchwordbefore, source, Posi) > Posi) do begin Dec(Posi); end; Ergebnis := Copy(source, Posi + length(searchwordbefore), Anfang - (Posi + length(searchwordbefore))); if (Ergebnis <> '') or (Ergebnis <> ' ') then liste.Add(addbefore + Ergebnis + addafter); end; end; end else //if reversesearch = false: begin if continuesearch then begin //if continuesearch = true: Ende := 0; Anfang := PosEX(searchwordbefore, source, Ende); while Anfang > 0 do begin Anfang := PosEX(searchwordbefore, source, Ende); if Anfang > 0 then begin Ende := PosEX(searchwordafter, source, Anfang); Ergebnis := Copy(source, Anfang + length(searchwordbefore), (Ende - Anfang) - length(searchwordbefore)); if (Ergebnis <> '') or (Ergebnis <> ' ') then liste.Add(addbefore + Ergebnis + addafter); Anfang := Anfang + length(Ergebnis); end; end; end else //if continuesearch = false: begin Ende := 0; Anfang := PosEX(searchwordbefore, source, Ende); if Anfang > 0 then begin Ende := PosEX(searchwordafter, source, Anfang); Ergebnis := Copy(source, Anfang + length(searchwordbefore), (Ende - Anfang) - length(searchwordbefore)); if (Ergebnis <> '') or (Ergebnis <> ' ') then liste.Add(addbefore + Ergebnis + addafter); end; end; end; end;
Code:
How To Use:
procedure PosExUltra(source, searchwordbefore, searchwordafter, addbefore, addafter: string; continuesearch, reversesearch: boolean; liste: Tstringlist);
In "source" befindet sich der große Text, den man Filtern möchte. "searchwordbefore" ist der Text, der sich VOR dem Wort was man will befindet. "searchwordafter" ist der Text, der sich NACH dem Wort was man will befindet. "addbefore" ist der Text, den man alternativ VOR dem GEFUNDENEN Wort anhängt. "addafter" ist der Text, den man alternativ NACH dem GEFUNDENEN Wort anhängt. "continuesearch": Es durchsucht den gesamten Text, wenn es MEHRERE Ergebnisse gibt (z.B. ALLE URLS), bei False bricht es nach dem 1. Fund ab. "reversesearch": Wenn "searchwordbefore" zu klein oder zu allgemein (zu oft vorkommend, oder gar variabel ist), dann sucht es erst nach "searchwordafter" und geht dann rückwärts, bis er "searchwordbefore" gefunden hat. Bsp: <ID=20>TEXT1<hierimmergleich> <ID=25>TEXT2<hierimmergleich> <ID=30>TEXT3<hierimmergleich> und man möchte alle!
Delphi-Quellcode:
Beispiele:
uses ... StrUtils;
public stringlist: TStringList; --- stringlist := TStringList.Create; source := 'groooßer Text mit Inhalt was ich will'; // wahlweise Absätze und Leerzeichen entfernen, um ein Besseres Ergenbis zu bekommen oder // weiteren Text zur Filterung zu erhalten: //source := StringReplace(source, ''#$A'', '', [rfReplaceAll]); //source := StringReplace(source, ''#13'', '', [rfReplaceAll]); //source := StringReplace(source, ' ', '', [rfReplaceAll]); //continue, reverse PosExUltra(source, 'VORDEMTEXT', 'NACHDEMTEXT', '', '', true, false, stringlist); stringlist.free; Einfache Vorwärtssuche bei eindeutigen Worten:
Delphi-Quellcode:
Man möchte alle URL Links, die mit .com aufhören haben:
source := '<text>DASWILLICH</text>';
PosExUltra(source, '<text>', '</text>', '', '', true, false, stringlist); //Suchwörter für Anfang und Ende sind leicht Filterbar, man kann vorwärts suchen.
Delphi-Quellcode:
Schwierige Stelle zum Suchen: Die Rückwärtssuche!
source := 'blatext xD [url]http://imagexxx.com[/url] und weiter text';
PosExUltra(source, 'http://', '.com', 'http://', '.com', true, false, stringlist); //Suchwörter für Anfang und Ende sind leicht Filterbar, man kann vorwärts suchen. //Da "http://" und ".com" abgeschnitten werden, fügen wir das dem gefundenen Wort nacher wieder an. Nehmen wir an, der Text wäre:
Code:
Der Anfangs und End Suchwert wäre:
source :=
<td>[url="?content=dictionary&task=term&dir=bla&ID=456"]DASWILLICH[/url]</td> <td style="line-height: 6pt;"> Anfang: '">' Ende: '</a></td>' Das würde nicht funktionieren, da Anfang SEHR häufig vorkommt. Also geht man zuerst so vor:
Delphi-Quellcode:
Das würde dann so aussehen:
source := StringReplace(source, ''#$A'', '', [rfReplaceAll]);
source := StringReplace(source, ''#13'', '', [rfReplaceAll]); source := StringReplace(source, ' ', '', [rfReplaceAll]);
Code:
nun kann man einfach die Rückwärtssuche bemühen, sie sucht zuerst nach Ende, und geht dann rückwärts bis er Anfang findet:
source := <td>[url="?content=dictionary&task=term&dir=bla&ID=456"]DASWILLICH[/url]</td><tdstyle="line-height:6pt;">
Delphi-Quellcode:
source := '<td>[url="?content=dictionary&task=term&dir=bla&ID=456"]DASWILLICH[/url]</td><tdstyle="line-height:6pt;">';
PosExUltra(source, '">', '</a></td><tdstyle="line-height:6pt', '', '', true, true, stringlist); Mfg Novo |
Re: PosExUltra - Ultimative Stringsuche/Parser
Sowas wie
Delphi-Quellcode:
bitte durch
if reversesearch = true then
Delphi-Quellcode:
ersetzen (die Gründe wurden schon oft im Forum erwähnt)
if reversesearch then
Und der Name ist definitiv verwirrend, denn gesucht wird hier nix, also nicht entsprechend des Funktionsergebnisses. StringReplaceUltra wäre da schon besser. |
Re: PosExUltra - Ultimative Stringsuche/Parser
Zitat:
Zitat:
Klar wird hier gesucht! ist sozusagen eine bessere PosEx -> PosExUltra :) |
Re: PosExUltra - Ultimative Stringsuche/Parser
Jupp, "StringReplace" wäre falsch. Es wird zwar nicht die Position zurückgegeben (also doch eher kein "PosEx"), aber es wird gesucht.
Zitat:
![]() Deine Funktion sieht viel versprechend aus bzw. was sie alles kann. Kannst du etwas über die Performance sagen, da du schreibst, sie sei für große Texte geeignet? Es gibt zahlreiche, schnelle Suchalgorithmen (Rabin-Karp & Co.), aber du verwendest keinen davon, wenn ich das richtig sehe. |
Re: PosExUltra - Ultimative Stringsuche/Parser
Das ist eine nette Funktion. Nenne sie doch lieber
Delphi-Quellcode:
Der Zusatz 'Ultra' erinnert so an Waschmittel.
Function PosEierlegendeWollmilchSau
Im Ernst: Was kann die Funktion, was ein TRegExpr nicht kann? |
Re: PosExUltra - Ultimative Stringsuche/Parser
Zitat:
Ein Beispiel: ![]() 800 Wörter -> Vorwärts -> SAUSCHNELL ( ja ich weis ist XML, dazu gibts ne XML Komponente, die bekomm ich aber partout nicht zum laufen :( FAIL ) ![]() Das gleiche mit ebenfalls 800 Wörter -> Rückwärtssuche nötig -> 30 Sekunden lang 25% CPU auslastung :D Sind aber schon heftig viele Zeilen. Wenn man z.B. Quellcode von Youtube parst, um die Video ID zu finden, ist das ruckzuck! Zitat:
|
Re: PosExUltra - Ultimative Stringsuche/Parser
Ich hätte aer noch was:
Delphi-Quellcode:
Dieses hat in soeiner Funktion besser nichts drin zu suchen.
Application.ProcessMessages;
|
Re: PosExUltra - Ultimative Stringsuche/Parser
Zitat:
|
Re: PosExUltra - Ultimative Stringsuche/Parser
Zitat:
|
Re: PosExUltra - Ultimative Stringsuche/Parser
Zitat:
Mal schaun, ob das denn funktioniert, bin mal weiter am Rumbasteln. Falls du es schon kannst, codeschnipsel :) |
Re: PosExUltra - Ultimative Stringsuche/Parser
Ich würde die genannte Zeile einfach löschen. Der, der deine Funktion nutzen möchte, soll diese selbst in einen Thread auslagern. Da musst du nichts basteln. ;)
|
Re: PosExUltra - Ultimative Stringsuche/Parser
ok habs mal verbessert.
|
Re: PosExUltra - Ultimative Stringsuche/Parser
Wenn eine Funktion oft sehr lange dauert:
Was du da machen könntest, wäre eine alternativer Parameter, bei welchem man eine Callback-Funktion angeben kann ... dort könnte der Benutzer deiner Funktion dann selber entscheiden, wie er dieses bei sich behandelt. Wobei man bei sowas eigentlich Funktion besser in Threads auslagert. PS: Wenn in deinem Code auf Application zugegriffen würde, dann könnte man diese Funktion nicht in einen Thread auslagern. Allgemein sollte bei derartigen Funktionen sowieso nicht auf Externes zugegriffen werden (dazu zählen Application oder eine Form). |
Re: PosExUltra - Ultimative Stringsuche/Parser
So, ich hab mich auch mal versucht und kurz getestet.
Delphi-Quellcode:
Die ganzen Sonderfälle (leere Suchstrings usw) habe ich nicht abgefangen.
Procedure ExtractBetween (Const aSource, aPrefix, aSuffix : String;
aFindAll : Boolean; aNewPrefix, aNewSuffix : String; aWords : TStrings); Var PrefixLength, PosPrefix, PosSuffix, BestPos : Integer; Begin PosPrefix := PosEx (aPrefix, aSource, 1); if PosPrefix=0 then exit; PrefixLength := Length (aPrefix); Repeat PosSuffix := PosEx (aSuffix, aSource, PosPrefix + PrefixLength); if PosSuffix=0 then Exit; While (PosPrefix<>0) and (PosPrefix<PosSuffix) Do Begin BestPos := PosPrefix; PosPrefix := PosEx (aPrefix, aSource, PosPrefix + PrefixLength); End; sWords.Add (aNewPrefix + Copy (aSource, BestPos+PrefixLength,PosSuffix-BestPos-PrefixLength) + aNewSuffix); If PosPrefix=0 then exit; Until not aFindall; End; |
Re: PosExUltra - Ultimative Stringsuche/Parser
Benötigte Unit: StrUtils, Classes
Novo überarbeitet:
Delphi-Quellcode:
alzaimar überarbeitet:
procedure PosExUltra(source, searchwordbefore, searchwordafter,
addbefore, addafter: string; continuesearch, reversesearch: boolean; liste: TStrings); function Search(var Anfang, Ende, Posi: Integer): string; var P: Integer; begin P:=PosEx(searchwordbefore, source, Posi); while (P = 0) or (P > Posi) do begin Dec(Posi); P:=PosEx(searchwordbefore, source, Posi); end; Result := Copy( source, Posi + length(searchwordbefore), Anfang - (Posi + length(searchwordbefore)) ); if (Result <> '') or (Result <> ' ') then liste.Append(addbefore + Result + addafter); end; var Anfang, Ende, Posi: Integer; Ergebnis: string; begin Ende := 0; if reversesearch then begin if continuesearch then begin Anfang := PosEx(searchwordafter, source, Ende); while Anfang > 0 do begin Posi := Anfang; if Anfang > 0 then begin Ergebnis:=Search(Anfang, Ende, Posi); Ende := Posi + length(searchwordbefore) + Length(Ergebnis) + Length(searchwordafter); Anfang := PosEX(searchwordafter, source, Ende); end; end; end else begin Anfang := PosEx(searchwordafter, source, Ende); Posi := Anfang; if Anfang > 0 then Ergebnis:=Search(Anfang, Ende, Posi); end; end else if continuesearch then begin repeat Anfang := PosEx(searchwordbefore, source, Ende); if Anfang > 0 then begin Ende := PosEx(searchwordafter, source, Anfang); Ergebnis := Copy( source, Anfang + length(searchwordbefore), (Ende - Anfang) - length(searchwordbefore) ); if (Ergebnis <> '') or (Ergebnis <> ' ') then liste.Append(addbefore + Ergebnis + addafter); Anfang := Anfang + length(Ergebnis); end; until Anfang = 0; end else begin Anfang := PosEx(searchwordbefore, source, Ende); if Anfang > 0 then begin Ende := PosEx(searchwordafter, source, Anfang); Ergebnis := Copy( source, Anfang + length(searchwordbefore), (Ende - Anfang) - length(searchwordbefore) ); if (Ergebnis <> '') or (Ergebnis <> ' ') then liste.Append(addbefore + Ergebnis + addafter); end; end; end;
Delphi-Quellcode:
procedure ExtractBetween(const aSource, aPrefix, aSuffix : string;
aFindAll : Boolean; aNewPrefix, aNewSuffix : string; aWords : TStrings); var PrefixLength, PosPrefix, PosSuffix, BestPos : Integer; begin PosPrefix := PosEx(aPrefix, aSource, 1); if PosPrefix > then begin PrefixLength := Length (aPrefix); repeat PosSuffix := PosEx(aSuffix, aSource, PosPrefix + PrefixLength); if PosSuffix > 0 then begin while (PosPrefix <> 0) and (PosPrefix < PosSuffix) do begin BestPos := PosPrefix; PosPrefix := PosEx(aPrefix, aSource, PosPrefix + PrefixLength); end; aWords.Append( aNewPrefix + Copy(aSource, BestPos + PrefixLength, PosSuffix-BestPos - PrefixLength) + aNewSuffix ); end; until not aFindall or (PosPrefix = 0); end; end; |
Re: PosExUltra - Ultimative Stringsuche/Parser
Hi omata,
Danke. |
Re: PosExUltra - Ultimative Stringsuche/Parser
Hallo omata,
da hat sich ein kleiner Copy&Paste-Fehler in der 2. Procedure versteckt: In
Delphi-Quellcode:
sollte die letzte Zeile wohl so lauten:
procedure ExtractBetween(const aSource, aPrefix, aSuffix : string;
aFindAll : Boolean; aNewPrefix, aNewSuffix : string; aWords : TStrings); var PrefixLength, PosPrefix, PosSuffix, BestPos : Integer; begin PosPrefix := PosEx(aPrefix, aSource, 1); if PosPrefix > then begin
Delphi-Quellcode:
Gruß,
if PosPrefix > 0 then begin
Stefan |
Re: PosExUltra - Ultimative Stringsuche/Parser
Hallo,
noch einige Anmerkungen: - Wenn aPrefix gefunden wird, aSuffix aber nicht, kommt es zu einer Endlosschleife für aFindAll = True. Im Code von alzaimar war dieser Fall durch eine Exit-Anweisung abgedeckt. - Der Compiler warnt, dass die Variable BestPos möglicherweise nicht initialisiert wird. - Das Füllen der Stringliste sollte mit einem BeginUpdate..EndUpdate geklammert werden. Ist eine Routine mit sieben bzw. acht Parametern wirklich sinnvoll? Wie testet man solch ein Ungetüm? Gruß Hawkeye |
Re: PosExUltra - Ultimative Stringsuche/Parser
Zitat:
|
Re: PosExUltra - Ultimative Stringsuche/Parser
Zitat:
Zitat:
Hier die Korrektur...
Delphi-Quellcode:
procedure ExtractBetween(const aSource, aPrefix, aSuffix : string;
aFindAll : Boolean; aNewPrefix, aNewSuffix : string; aWords : TStrings); var PrefixLength, PosPrefix, PosSuffix, BestPos : Integer; begin PosPrefix := PosEx(aPrefix, aSource, 1); if PosPrefix > 0 then begin PrefixLength := Length (aPrefix); repeat PosSuffix := PosEx(aSuffix, aSource, PosPrefix + PrefixLength); if PosSuffix > 0 then begin while (PosPrefix <> 0) and (PosPrefix < PosSuffix) do begin BestPos := PosPrefix; PosPrefix := PosEx(aPrefix, aSource, PosPrefix + PrefixLength); end; aWords.Append( aNewPrefix + Copy(aSource, BestPos + PrefixLength, PosSuffix-BestPos - PrefixLength) + aNewSuffix ); end; until not aFindall or (PosSuffix = 0) or (PosPrefix = 0); end; end; |
Re: PosExUltra - Ultimative Stringsuche/Parser
Zitat:
Bei deiner Suche klappt sogar eine Suche nach:
Delphi-Quellcode:
und:
">
Delphi-Quellcode:
obwohl
</a></td>
Delphi-Quellcode:
SEHR häufig vorkommt.
">
Ausserdem scheint deine Funktion schneller zu sein, als meine, weniger Code ist es auf jedenfall. Respekt und danke! Mfg Novo |
Re: PosExUltra - Ultimative Stringsuche/Parser
Gibt es einen bestimmten Grund, warum Du
Delphi-Quellcode:
verwendest und nicht
procedure ExtractBetween(const aSource, aPrefix, aSuffix : string;
aFindAll : Boolean; aNewPrefix, aNewSuffix : string; aWords : TStrings);
Delphi-Quellcode:
?
procedure ExtractBetween(const aSource, aPrefix, aSuffix : string;
const aFindAll : Boolean; const aNewPrefix, aNewSuffix : string; var aWords : TStrings); Da bei keinem der Parameter eine Wertzuweisung stattfindet, kann man sie ohne Probleme auch alle als Konstanten deklarieren, mit Ausnahme vom aWords. Der muss als Var-Parameter deklariert werden, da ja dort die Ergebnisse gespeichert werden. Man könnte das ganze auch noch eleganter mittels
Delphi-Quellcode:
umsezen. In diesem Fall bräuchte man aFindAll nur dann zu übergeben, wenn nur der erste Treffer zurückgegeben werden soll.
procedure ExtractBetween(const aSource, aPrefix, aSuffix : string;
const aNewPrefix, aNewSuffix : string; var aWords : TStrings; const aFindAll : Boolean = True); Um das ganze richtig elegant zu machen, würde ich das ganze so umbauen:
Delphi-Quellcode:
dann kann man sich den Parameter aWords nämlich komplett sparen :wink:
function ExtractBetween(const aSource, aPrefix, aSuffix, aNewPrefix, aNewSuffix : string;
const aFindAll : Boolean = True): TStrings; var PrefixLength, PosPrefix, PosSuffix, BestPos : Integer; begin PosPrefix := PosEx(aPrefix, aSource, 1); if (PosPrefix > 0) then begin PrefixLength := Length (aPrefix); repeat PosSuffix := PosEx(aSuffix, aSource, PosPrefix + PrefixLength); if (PosSuffix > 0) then begin while (PosPrefix <> 0) and (PosPrefix < PosSuffix) do begin BestPos := PosPrefix; PosPrefix := PosEx(aPrefix, aSource, PosPrefix + PrefixLength); end; Result.Append( aNewPrefix + Copy(aSource, BestPos + PrefixLength, PosSuffix-BestPos - PrefixLength) + aNewSuffix ); end; until not aFindall or (PosSuffix = 0) or (PosPrefix = 0); end; end; |
Re: PosExUltra - Ultimative Stringsuche/Parser
Hallo Heiko,
Zitat:
Gruß Hawkeye |
Re: PosExUltra - Ultimative Stringsuche/Parser
Zitat:
|
Re: PosExUltra - Ultimative Stringsuche/Parser
Richtig. Ich selbst deklariere übergebene Objekte immer als const, damit ich mir nicht versehentlich "ins Knie schieße", indem ich die Referenz ändere.
|
Re: PosExUltra - Ultimative Stringsuche/Parser
Übrigens musst du bei Objektreferenzen kein var davor schreiben.
Du bekommst ja quasi einen Pointer auf die Stringliste und den änderst du ja nicht, also kein Grund für var ;) Und wie bereits gesagt wurde ist const sogar angebrachter. MfG Fabian |
Re: PosExUltra - Ultimative Stringsuche/Parser
Zitat:
Ausserdem geht das nichtmal:
Delphi-Quellcode:
Bei:
ListBox1.Items.AddStrings(FuncExtractBetween(source, '[img]', '[/img]</img>', '', '', True));
Code:
mal alle album links ziehn.
<img src="http://blub.de
" alt="album"></img> <img src="http://blub.de " alt="bild"></img> <img src="http://blub.de " alt="bild"></img> <img src="http://blub.de " alt="album"></img> <img src="http://blub.de " alt="album"></img> <img src="http://blub.de " alt="bild"></img> <img src="http://blub.de " alt="album"></img> öhm und ist die rückwärtssuche nun wirklich überflüssig? |
Re: PosExUltra - Ultimative Stringsuche/Parser
Jau, das mit der direkten Zuweisung der TStrings als Funktionsrückgabe funktioniert wirklich nicht.
Beim ersten Zugriff auf Results in der Funktion (z.B. durch Results.Beginupdate oder .Append) kommt eine Read/write access exception. Weiss jemand, warum das nicht geht und ob es da einen Trick gibt? |
Re: PosExUltra - Ultimative Stringsuche/Parser
Das dürfte daran liegen, dass Result nirgends erzeugt wird. Aber wie bereits weiter oben gesagt sollte man das Objekt besser an die Routine übergeben, sonst fängt man sich schnell ein Speicherleck ein.
|
Re: PosExUltra - Ultimative Stringsuche/Parser
Moin,
naja wo ist denn das Objekt erstellt worden? Vorgesehen war es eigentlich das dies außerhalb passiert, aber wenn die nun zurückgegeben wird, musst du es wohl in der Funktion erstellen. Allerdings gewöhne dir das lieber nicht an, weil das ist nicht gerade sauberer Stil. Es stellt sich nämlich die Frage, wo wird das denn wieder freigegeben? Bei der ursprünglichen Version war das klar:
Delphi-Quellcode:
Bei der veränderten Fassung, kannst du das nicht mehr so strikt trennen. Deshalb ist der Trick, nimm die Fassung von omata (oder?):
var
o : TObject; begin o := TObject.Create; try func(o); // do sth. finally o.Free; end;
Delphi-Quellcode:
Nebenbei, wenn der letzte Parameter ein var-Parameter wäre, geht das glaub ich nicht, weil TCustomMemo.Lines eine Property ist.
ExtractBetween(…, Memo.Lines);
MfG Fabian |
Re: PosExUltra - Ultimative Stringsuche/Parser
Erzeugt und wieder freigegeben habe ich die Stringlist natürlich ausserhalb, eine Property ist diese ja auch nicht:
Delphi-Quellcode:
slSplitString:=TStringList.Create;
try slSplitString:=ExtractBetween(dummy, 'http://', '.de', '', '', true); Memo.Lines.AddStrings(slSplitString); finally slSplitString.Free; end; |
Re: PosExUltra - Ultimative Stringsuche/Parser
Und damit hast Du Dir die Referenz der erzeugten Liste mit einer nichtexistenten überschrieben. Mach es doch wie vorgeschlagen: übergib die Liste als (const-)Parameter und alles wird gut :)
[edit] Da waren mir zu viele "und"s drin :mrgreen: [/edit] |
Re: PosExUltra - Ultimative Stringsuche/Parser
Hab ich schon längst wieder gemacht. :)
Es ging mir nur darum, zu verstehen, was hier schief läuft. Danke für die Infos und die Geduld. |
Re: PosExUltra - Ultimative Stringsuche/Parser
Hast du es schon bereits verstanden? :D
Ansonsten eine kleine Erklärung: Du gibst mit der Funktion via Result etwas zurück. Das macht auch deine Zuweisung deutlich. Wenn man schreibt a := b dann schreibt man quasi den Inhalt von b in a. Das Problem dabei ist, das du nirgends der Funktion sagst, wie denn das erstellte Objekt lautet, dass zurückgegeben wird. Ich mach mal ein Beispiel:
Delphi-Quellcode:
Das ist quasi dein Beispiel: Du initialisierst a und schreibst dann den Wert der Funktion rein, und versuchst a in der Funktion zu benutzen. Wahrscheinlich steht nachher im Dialog 0, weil Result normalerweise mit 0 initalisiert wird. Wenn man das jetzt etwas umschreibt und die Funktion umgeht sieht das dann so aus (woraus klar werden dürfte, warum das nicht geht):
function answer : Integer;
begin Result := 42 * Result; end; var a : Integer; begin a := 10; a := answer; ShowMessage(IntToStr(a)); end;
Delphi-Quellcode:
Das heißt, Result ist wie eine lokale Variable und nur in der Funktion sichtbar, womit es nicht den Wert von a hat.
var
a, b : Integer; begin a := 10; // Code von answer b := 42 * b; a := b; ShowMessage(IntToStr(a)); end; Ich hoffe das ist soweit verständlich. MfG Fabian PS: Es kann auch sein, dass a ≠ 0 ist, weil man nicht sicher sein kann, mit was Result oder b initalisiert werden. In der Regel wird a aber 0 sein ;) |
Re: PosExUltra - Ultimative Stringsuche/Parser
Jetzt hats Klick gemacht, danke.
Schon witzig, wenn einem so ein Grundlagenproblem nach vielen Jahren Programmiertätigkeit noch nicht untergekommen ist. |
Re: PosExUltra - Ultimative Stringsuche/Parser
Um das noch weiter auszuführen: TStrings ist ja eine Klasse. Will man nun ein Objekt dieser Klasse in einer Funktion zurückgeben, muss sie auch innerhalb der Klasse Funktion instanziert werden. Da aber die Freigabe nicht innerhalb des Blocks (also der Funktion) erfolgen kann, in dem sie instanziert wurde (der Rückgabewert wäre ja sonst hinfällig), muss man sehr genau aufpassen, dass man sich kein Speicherleck einfängt. Aus genau diesem Grund gilt diese Vorgehensweise als unschön. Der einzige mir bekannte sinnvolle Einsatzzweck einer Funktion, die ein Objekt zurückgibt, ist der Getter einer Property. Es mag evtl. noch weitere geben, aber es fallen mir spontan keine ein. Zur angesprochenen Property aber noch schnell ein Beispiel:
Delphi-Quellcode:
Der Sinn einer solchen Vorgehensweise liegt darin, Objekte erst dann zu erzeugen, wenn diese auch wirklich gebraucht werden, im obigen Beispiel also beim ersten Zugriff auf die Property.
type
TMyClass = class private //privates Feld vom Typ der Klasse (initial nil) FStrings: TStrings; //Getter-Methode function GetStrings: TStrings; public //Property property Strings: TStrings read GetStrings; end; ... function TMyClass.GetStrings: TStrings; begin if not Assigned(FStrings) then FStrings := TStringlist.Create; Result := FStrings; end; [edit] Blödsinn korrigiert (s.o.) [/edit] |
Re: PosExUltra - Ultimative Stringsuche/Parser
Zitat:
In beiden Fällen wird eine Referenz auf eine Objektvariable erwarted, damit ist die direkte Übergabe von TStrings-Property nicht möglich. Vor Parametern für einfache Datentypen ohne Referezzählung braucht auch kein const zu stehen. Ein Boolean nimmt auf dem Stapel ebenso viel Speicher ein, wie ein Zeiger auf eine Boolean-Variable/Konstante. Innerhalb der Prozedur kann einfacher auf den Wert zugegriffen werden, als diesen bei jedem Zugriff über den Zeiger zu lesen/schreiben. Mein Vorschlag:
Delphi-Quellcode:
procedure ExtractBetween(const aSource, aPrefix, aSuffix, aNewPrefix, aNewSuffix : string;
aWords : TStrings; aFindAll : Boolean = True); |
Re: PosExUltra - Ultimative Stringsuche/Parser
Zitat:
Delphi-Quellcode:
Komischerweise funktioniert das bei mir, obwohl ich das wohl schon seit Jahren falsch mache.
procedure FillWithNumbers(const aList: TStrings);
var i: integer; begin aList.Clear; for i := 0 to 100 do aList.Add(Format('%d',[i])); end; procedure TForm1.FormCreate(Sender: TObject); begin FillWithNumbers(Memo1.Lines); end; |
Re: PosExUltra - Ultimative Stringsuche/Parser
Ich vermute, er verwechselt das mit var was natürlich nicht geht ;)
MfG Fabian |
Re: PosExUltra - Ultimative Stringsuche/Parser
Ich habe mich zu kurz und damit falsch ausgedrückt :oops:
Zitat:
Zitat:
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:37 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