![]() |
Substrings Extract Delimited Values
Liste der Anhänge anzeigen (Anzahl: 1)
Ich würde gerne aus einem bestehenden String mit einem Delimiter gekennzeichnete Substrings extrahieren und in eine liste (hier: zu Testzwecken Tstrings, später eine custom DB / Trie exportieren).
Nun habe ich folgende Methode zur Extraktion, die aber extrem langsam scheint. Fällt Euch etwas ein, um die EXtraktion hier zu beschleunigen? Macht es Sinn mit Pchar zu arbeiten? Vielen Dank für Eure Ideen :) Vollst. Testcode:
Delphi-Quellcode:
Ebenfalls beigefügt.
Program Extractsubstrings;
{$APPTYPE CONSOLE} {$R *.res} // {$define unittests} Uses Classes, Generics.Collections, System.SysUtils {$IFDEF unittests}, Unittests{$ENDIF}; Const Charsize = 2; Procedure Testextractsubstrings(Const Str: String; Delimiter: Char; Items: Tlist<String> { class to be replaced by custom list or tree class } ); Var I, J, Len: Integer; P, Q, Oldp: Pchar; Itemtoadd: Pchar; Newpos, Oldpos: Integer; Begin Assert(Assigned(Items)); I := 0; Len := Length(Str); P := Pchar(Str); J := 1; Oldp := P; Oldpos := 0; While P <> '' Do Begin Inc(I); If P^ = Delimiter Then Begin Q := Oldp - I + 1; Getmem(Itemtoadd, (I - 1) * Charsize); Strlcopy(Itemtoadd, Q, I - 1); Items.Add(Itemtoadd); Freemem(Itemtoadd); Oldpos := Length(Itemtoadd); I := 0; End; Oldp := P + 1; Inc(P); End; // add last item While P^ <> Delimiter Do Dec(P); Itemtoadd := P + 1; Items.Add(Itemtoadd); // Writeln(Itemtoadd); End; Var I: Integer; S: String; List: Tlist<String>; Const _max = 100000; Begin Writeln('Extracting comma-delimited substrings. Testprogram'); Try S := ''; For I := 1 To _max Do S := S + Inttostr(I) + ','; Delete(S, Length(S), 1); // Writeln(S); List := Tlist<String>.Create; {$IFDEF unittests} Tester.Test_leakProc( Procedure {$ENDIF} Begin Writeln('Starting test. Please wait'); Testextractsubstrings(S, ',', List); Assert(List.Count = _max); List.Free; End{$IFDEF unittests}){$ENDIF}; Writeln('Test finished'); { TODO -oUser -cConsole Main : Insert code here } Except On E: Exception Do Writeln(E.ClassName, ': ', E.Message); End; Writeln('Test finished. Press any key to quit'); ReadlN; End. |
AW: Substrings Extract Delimited Values
Wozu das GetMem und FreeMem?
Einfach mit Copy diesen Teil aus dem String holen. Erspart auch die von dir vergessenen Ressourcenschutzblöcke. PS: ![]() ![]() oder ![]() oder ![]() ![]() oder ... Statt Listen (Objekten) verwende ich gern Arrays ([OH]TArray<string>[/OH], bzw. das uralte ![]() |
AW: Substrings Extract Delimited Values
Zitat:
Delphi-Quellcode:
Ohne Gewähr!
const
MAX_COUNT = 100000; function GetNextItem(const pmcDelimiter: Char; pmSrcPos: PChar; out pmNextPos: PChar): String; var pStart: PChar; begin if pmSrcPos = Nil then begin pmNextPos := pmSrcPos; Exit(''); //=> end; while pmSrcPos^ in [#9, ' '] do Inc(pmSrcPos); // Trim left pStart := pmSrcPos; repeat if pmSrcPos^ = #0 then begin pmNextPos := Nil; Break; //=> end else if pmSrcPos^ = pmcDelimiter then begin pmNextPos := pmSrcPos + 1; Break; //=> end else Inc(pmSrcPos); until False; while (pmSrcPos > pStart) and (pmSrcPos[-1] in [#9, ' ']) do Dec(pmSrcPos); // Trim right SetString(Result, pStart, pmSrcPos - pStart); end; var p: PChar; src: String; timer: TPrecisionTimer; begin for var i: Integer := 1 to MAX_COUNT do src := src + i.ToString + ','; Delete(src, Length(src), 1); var sList := TStringList.Create; try timer.Start; p := PChar(src); while p <> Nil do sList.Add(GetNextItem(',', p, p)); ShowMessage(Format('Count: %d, Time: %s', [sList.Count, timer.Stop])); finally sList.Free; end; Bis bald... Thomas |
AW: Substrings Extract Delimited Values
Warum nicht einfach:
Delphi-Quellcode:
Oder habe ich etwas falsch verstanden?
var
SL: TStringList; begin SL := TStringList.Create; SL.Delimiter := ADelimiter; SL.StrictDelimieter := True; SL.DelimitedText := AText; ... |
AW: Substrings Extract Delimited Values
Zitat:
Bis bald... Thomas |
AW: Substrings Extract Delimited Values
Das Anfügen an die TStringList benötigt aber ja auch seine Zeit.
Einen wohl auch akzeptabel schnellen Ansatz bietet das bordeigene Split:
Delphi-Quellcode:
var arr := src.Split([',']);
|
AW: Substrings Extract Delimited Values
Zitat:
Bis bald... Thomas |
AW: Substrings Extract Delimited Values
Zitat:
aber wenn es unbedingt sein muß, dann
Delphi-Quellcode:
vor dem Hinzufügen. :lol:
SL.Capacity := 1000000;
|
AW: Substrings Extract Delimited Values
Wenn Geschwindigkeit so eine Rolle spielt - was ich mir bei einer DB gar nicht so recht vorstellen kann - dann wäre es eine Idee den String nicht vorgängig aufzusplitten und das Ergebnis zu speichern sondern erst später die String zu extrahieren und gleich zu verwenden.
Und wenn es doch sein muss nicht die ganzen strings zu speichern sondern nur die Start- und End-Positionen im Ausgangsstring. |
AW: Substrings Extract Delimited Values
Danke Euch für Eure Vorschläge!
Die Lösung mit
Delphi-Quellcode:
macht bisher einen guten Eindruck. Die Lösung von Thomas / mytbo werde ich noch prüfen
s.split()
Zu den spezifischen Anforderungen wäre nur noch zu sagen: - ich lade zzt eine Liste mit min 50M, max 100M, kommaseparierten (CSV) Einträgen vorberechnteter / vordefinierter Strings aus einer *.zip- Resource - Ziel: es ist im Anschluss zu prüfen ob ein bestimmter Wert in dieser/n Liste/n vorkommt. Daher (denke ich) müsste ich die Resource bei programmstart durchsuchbar laden - ich hatte überlegt, zwecks Speicherreduktion die Werte in einem (Binary-)Trie zu speichern (hier werden nicht die kompletten Strings gespeichert) statt in einer Stringlist / Tlist<>. Allerdings muss ich da noch überprüfen, inwiefern da die Geschwindigkeitseinbüßen zum durchsuchen meines Tries relevant sind. -Ggf hatte ich überlegt, direkt auf Datenbank umzusteigen Die Resourcen sind derzeit in einem Zip archiv (einzelne *.txt files) hinterlegt, Gäbe es hier eine Möglichkeit, ggf direkt auf den Zipstream zuzugreifen und darin zu suchen - statt extraktion/ übertragung von dort, oder macht das eher keinen Sinn? Weitere Anforderungen an Format / Speicherung gibt es vorerst keine.> @himitsu, wahrscheinlich wird es nicht direkt ersichtlich, wie viele Einträge geladen werden. Das könnte ich allerdings hierzu noch anpassen, um die capacity zu setzen |
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:46 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