Autor Beitrag
Christian213
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 66
Erhaltene Danke: 3

Win XP, Win 7 64Bit
Lazarus 1.0.10
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2242
Erhaltene Danke: 55

Win10
VS Code, Delphi 2010 Prof.
BeitragVerfasst: 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

_________________
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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 66
Erhaltene Danke: 3

Win XP, Win 7 64Bit
Lazarus 1.0.10
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2242
Erhaltene Danke: 55

Win10
VS Code, Delphi 2010 Prof.
BeitragVerfasst: 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:

ausblenden 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 66
Erhaltene Danke: 3

Win XP, Win 7 64Bit
Lazarus 1.0.10
BeitragVerfasst: 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):
ausblenden 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// um kompatibel zu indexOf zu bleiben
    if Result > -1 then
      break;
  end;
end;
Christian213 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 66
Erhaltene Danke: 3

Win XP, Win 7 64Bit
Lazarus 1.0.10
BeitragVerfasst: Mi 17.07.13 11:29 
PS: Die Idee "Result" als Schleifenvariable zu benutzen gefällt mir - das klau' ich mal :-)
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 66
Erhaltene Danke: 3

Win XP, Win 7 64Bit
Lazarus 1.0.10
BeitragVerfasst: 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 :-)
ausblenden 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); // um kompatibel zu indexOf zu bleiben
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
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2242
Erhaltene Danke: 55

Win10
VS Code, Delphi 2010 Prof.
BeitragVerfasst: Mi 17.07.13 12:07 
user profile iconChristian213 hat folgendes geschrieben Zum zitierten Posting springen:
ausblenden 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); // um kompatibel zu indexOf zu bleiben
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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: 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...
ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2242
Erhaltene Danke: 55

Win10
VS Code, Delphi 2010 Prof.
BeitragVerfasst: Mi 17.07.13 13:29 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
ausblenden Delphi-Quelltext
1:
Exit(i);					
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)

_________________
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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 17.07.13 14:50 
user profile iconHidden hat folgendes geschrieben Zum zitierten Posting springen:
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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 66
Erhaltene Danke: 3

Win XP, Win 7 64Bit
Lazarus 1.0.10
BeitragVerfasst: Mi 17.07.13 14:55 
user profile iconHidden hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconChristian213 hat folgendes geschrieben Zum zitierten Posting springen:
ausblenden 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); // um kompatibel zu indexOf zu bleiben
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.