Autor |
Beitrag |
Christian213
      
Beiträge: 66
Erhaltene Danke: 3
Win XP, Win 7 64Bit
Lazarus 1.0.10
|
Verfasst: Mi 17.07.13 09:25
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
      
Beiträge: 2242
Erhaltene Danke: 55
Win10
VS Code, Delphi 2010 Prof.
|
Verfasst: 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?
Grüße,
Daniel
_________________ Centaur spears can block many spells, but no one tries to block if they see that the spell is a certain shade of green. For this purpose it is useful to know some green stunning hexes. (HPMoR)
|
|
Christian213 
      
Beiträge: 66
Erhaltene Danke: 3
Win XP, Win 7 64Bit
Lazarus 1.0.10
|
Verfasst: 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
      
Beiträge: 2242
Erhaltene Danke: 55
Win10
VS Code, Delphi 2010 Prof.
|
Verfasst: 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
_________________ Centaur spears can block many spells, but no one tries to block if they see that the spell is a certain shade of green. For this purpose it is useful to know some green stunning hexes. (HPMoR)
|
|
Christian213 
      
Beiträge: 66
Erhaltene Danke: 3
Win XP, Win 7 64Bit
Lazarus 1.0.10
|
Verfasst: 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 
      
Beiträge: 66
Erhaltene Danke: 3
Win XP, Win 7 64Bit
Lazarus 1.0.10
|
Verfasst: Mi 17.07.13 11:29
PS: Die Idee "Result" als Schleifenvariable zu benutzen gefällt mir - das klau' ich mal 
|
|
jaenicke
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: 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 
      
Beiträge: 66
Erhaltene Danke: 3
Win XP, Win 7 64Bit
Lazarus 1.0.10
|
Verfasst: 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
      
Beiträge: 2242
Erhaltene Danke: 55
Win10
VS Code, Delphi 2010 Prof.
|
Verfasst: 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;.
_________________ Centaur spears can block many spells, but no one tries to block if they see that the spell is a certain shade of green. For this purpose it is useful to know some green stunning hexes. (HPMoR)
|
|
jaenicke
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: 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
      
Beiträge: 2242
Erhaltene Danke: 55
Win10
VS Code, Delphi 2010 Prof.
|
Verfasst: Mi 17.07.13 13:29
jaenicke hat folgendes geschrieben : | Delphi-Quelltext |
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 
_________________ Centaur spears can block many spells, but no one tries to block if they see that the spell is a certain shade of green. For this purpose it is useful to know some green stunning hexes. (HPMoR)
|
|
jaenicke
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: 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 
      
Beiträge: 66
Erhaltene Danke: 3
Win XP, Win 7 64Bit
Lazarus 1.0.10
|
Verfasst: Mi 17.07.13 14:55
Hidden hat folgendes geschrieben : | 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;. |
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.
|
|
|