Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - "Gegenstück" zu IndexOf?
Christian213 - Mi 17.07.13 09:25
Titel: "Gegenstück" zu IndexOf?
Hallo,
ich brauche eine Art schnelles Gegenstück zu IndexOf bei TStringList: Meine StringList enthält eine Anzahl von Substrings, ich möchte nun einen von Außen übergebenen String mit diesen Substrings vergleichen. Leider funktioniert IndexOf ja genau anders herum.
Hat jemand eine Idee wie ich das Ganze OHNE iterieren mittels for...Schleife lösen kann? Gibt es eine Methode die man dafür missbrauchen könnte?
Danke!
Gruß,
Christian
Hidden - Mi 17.07.13 09:54
Hallo Christian,
Ich verstehe leider nicht, was genau du zu erreichen versuchst: IndexOf(S) liefert den Index des ersten Strings in der Stringlist, der mit S übereinstimmt (d.h. AnsiCompareText = 0).
So oft ich deinen Beitrag auch lese, bis auf das Wörtchen substring ist das genau was du beschreibst? :nixweiss:
Grüße,
Daniel
Christian213 - Mi 17.07.13 10:13
Ok, ich versuche mal die Ausgangslage etwas besser zu beschreiben:
- Ich habe eine StringList mit Dateipfad-Fragmenten (Teilstrings)
- Ich möchte nun prüfen, ob in einem übergebenen String mit einem absoluten Pfad einer dieser Teilstrings matcht
- Und das möglichst ohne eine Schleife bauen zu müssen
Hidden - Mi 17.07.13 10:33
ich weiß zwar nicht, in wiefern
IndexOf anders herum funktioniert, aber ob ein String in einem anderen als Substring enthalten ist kannst du mit
Pos(Substring, String
) herausfinden:
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| function FirstSubstring(const S: String, Str: TStrings): Integer; begin for Result := 0 to Str.Count - 1 do if System.Pos(S, Str[Result]) > 0 then Exit; Result := -1; end; |
Grüße,
Daniel
Christian213 - Mi 17.07.13 11:28
Mit "anders herum" meine ich, dass ich die Teilstrings in der Stringliste habe, deswegen habe ich es nun so gelöst (ähnelt aber Deinem Vorschlag):
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| function reverseIndexOf(StringList: TStringList; SearchString: AnsiString): Integer; var i : Integer; begin for i := StringList.Count-1 downto 0 do begin Result := (pos(StringList[i], SearchString)) - 1; if Result > -1 then break; end; end; |
Christian213 - Mi 17.07.13 11:29
PS: Die Idee "Result" als Schleifenvariable zu benutzen gefällt mir - das klau' ich mal :-)
jaenicke - Mi 17.07.13 11:30
Falls du relative Pfade meinst, würde ich die in absolute Pfade umwandeln und dann vergleichen.
Oder soll das eine Suche in allen Ordnern oder so sein? Dann ist das so wie du es hast natürlich passend.
Christian213 - Mi 17.07.13 11:39
@jaenicke: Zweiteres. Ich habe meine Methode mittels des Tricks von Hidden noch weiter optimiert. Ich denke mit dem Resultat kann ich leben :-)
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| function reverseIndexOf(StringList: TStringList; SearchString: AnsiString): Integer; begin for Result := StringList.Count-1 downto 0 do if pos(StringList[Result], SearchString) > 0 then break; dec(Result); end; |
Der Name "reverseIndexOf" ist sicherlich unglücklich gewählt, aber wie soll man eine Funktion nennen die eine Liste von Substrings gegen einen übergebenen String matcht?
Hidden - Mi 17.07.13 12:07
Christian213 hat folgendes geschrieben : |
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7:
| function reverseIndexOf(StringList: TStringList; SearchString: AnsiString): Integer; begin for Result := StringList.Count-1 downto 0 do if pos(StringList[Result], SearchString) > 0 then break; dec(Result); end; | |
Achtung, diese Version unterscheidet nicht länger zwischen den Fällen "
StringList[0] ist Substring von
SearchString" und "keiner der Strings in
Stringlist ist Substring von
SearchString". Ich nehme an,
dec(Result) sollte im letzten Fall sicherstellen, dass ebenfalls
-1 zurückgegeben wird?
Was ich oben gepostet hatte, war die Implementierung von
IndexOf aus der
TStringlist übergeordneten Klasse
TStrings in Classes.pas, Delphi 2010; nur, dass ich den Ausdruck
AnsiCompareText = 0 durch
Pos > 0 ersetzt habe. Für den Fall, dass die for-Schleife komplett durchläuft, steht dort noch ein
Result := -1;.
jaenicke - Mi 17.07.13 13:07
Der Wert einer Schleifenvariablen nach dem Durchlauf ist undefiniert (das ist dokumentiert, dass das so ist). Es ist daher Glückssache, ob das richtige herauskommt. Und es kann passieren, dass die Umstellung von Projekteinstellungen (Optimierung, ...) oder der Wechsel auf eine neuere Delphiversion dazu führen, dass es nicht mehr funktioniert.
Deshalb sollte man so etwas lieber richtig machen...
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| function reverseIndexOf(const StringList: TStringList; const SearchString: AnsiString): Integer; var i: Integer; begin for i := StringList.Count - 1 downto 0 do if Pos(StringList[i], SearchString) > 0 then Exit(i); Result := -1; end; |
Nebenbei führt bei neueren Delphiversionen (>= 2009) die Verwendung von AnsiString als Typ dazu, dass bei der Übergabe an Pos jedesmal eine Umwandlung in einen UnicodeString durchgeführt wird. Deshalb ist das auch keine gute Idee.
Hidden - Mi 17.07.13 13:29
Da hast du allerdings recht. Ich wollte das beim kopieren schon auf eine mehrzeilige Lösung ändern (
result := i; Exit;) oder die Schleife als
while do .. Inc(result) schreiben, aber da Classes.pas es so macht sollte es in dem Kontext ja funktionieren*.
Daran dass
Exit optional auch ein Argument kriegen kann, hatte ich nicht gedacht. Das ist keine Zeile länger und verhält sich mit Sicherheit wie erwartet.
Edit: Ok, wie es scheint ist der Wert der Schleifenvariablen durchaus definiert wenn die Schleife mit einem
Exit; gebrochen wird. Exit(i) ist trotzdem an der Stelle schöner, auch wenn es wohl nur für C++-Programmierer und ähnliche existiert, die gerne ein
return hätten 8)
jaenicke - Mi 17.07.13 14:50
Hidden hat folgendes geschrieben : |
Edit: Ok, wie es scheint ist der Wert der Schleifenvariablen durchaus definiert wenn die Schleife mit einem Exit; gebrochen wird. |
Das ist aber kein definiertes Verhalten und funktioniert nur, wenn in eax am Ende eben dieser Wert steht.
In XE4 zumindest wird ein entsprechender Assemblerbefehl durch den Compiler eingefügt, der den Wert am Ende in den Rückgabewert schreibt. Das liegt daran, dass die Schleifenvariable auf dem Stack geführt wird. Trotzdem heißt das nicht, dass das immer funktionieren muss, deshalb kommt ja auch die entsprechende Compilerwarnung.
Christian213 - Mi 17.07.13 14:55
Ja, stimmt. Das ist mir auch noch aufgefallen. Habe es entsprechend angepasst.
Was das POS angeht: Habe es nun in AnsiPos geändert. Ich verwendet zwar nur AnsiStrings, aber Ihr habt natürlich Recht.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!