Announcement

Collapse
No announcement yet.

Alle Substrings in String finden (mit Pos)

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Alle Substrings in String finden (mit Pos)

    Hallo,
    <p>ich habe eine Frage zur Pos-Funktion in Delphi. Die Pos-Funktion gibt den Index des ersten Auftretens eines Substrings in String zurück. Wie muss ich die Schleife bauen, damit ich sämtliche Vorkommen von Substring in String zurückerhalte?
    <p> Ein Beispiel: Ich suche nach dem Auftreten von SDF in asdafSDFbsdgSDFcsdf. Die Funktion soll mir die Werte 6 und 13 zurückliefern.
    <p>Danke im voraus
    <p>Gerhard.

  • #2
    Hallo Gerhard,<br>
    meiner erster Gedankde war folgender.<br>
    Schiebe den String in eine temporäre Variable z.B. TmpStr.<br>
    Wenn Du die erste Position des gesuchten SubStrings hast, dann merke dir die Position und ersetze den SubString in TmpStr<br>
    z.B. durch XXX. Dann wiederhole die Suche.<br&gt

    Comment


    • #3
      oder steige auf die Nutzung von PChars um (StrPos()). Der Resultpchar+Patternlength kann dann als nächster Startwert der Suche genutzt werden. Diese spart das expensive rumkopieren der Teilstrings in temporäre variablen

      Comment


      • #4
        Hallo Hagen,<p>
        manchmal fehlt mir ein kleines Teilstück zum Erfolg. Wie stelle ich denn bei StrPos() einen Startwert ein

        Comment


        • #5
          Hallo Hagen, <p>
          ich habe ein bisschen herumgespielt und folgende Lösung gefunden:
          <pre>
          procedure TForm1.Button1Click(Sender: TObject);
          var FN:integer; AStr, Substr:string; Me:PChar;
          begin
          AStr:='asfgDFAsdfafgDFAkljklöqDFAwqwer';
          Substr:='DFA';
          while StrPos(PChar(AStr),PChar(Substr)) <> nil do
          begin
          Me:=StrPos(PChar(AStr),PChar(Substr));
          FN:=Length(Astr)-Length(Me)+1;
          ShowMessage('FN ist '+IntToStr(FN));
          Me[0]:=Me[Length(Me)-Length(Substr)];
          Me:=StrPos(Me,PChar(Substr));
          end;
          end;
          </pre><p>
          Jetzt liefert FN das, was ich suche: die Indices der Substr-Vorkommen. Eine Frage habe ich noch: muss ich noch für Me Speicherplatz

          reservieren und freigeben? Wenn ja, wie (die Länge von Me ändert sich ja laufend)

          Comment


          • #6
            <pre>

            <code><font size=2 face="Courier New">Hm, sieht ein bißchen ungl&uuml;cklich aus, Du kannst einige StrPos aufrufe Einsparen
            <br>
            <b>var
            </b>Start,Cur: PChar;
            <b>begin
            </b>AStr := <font color="#0000FF">'asfgDFAsdfafgDFAkljklöqDFAwqwer'</font>;
            Substr := <font color="#0000FF">'DFA'</font>;
            Start := PChar(AStr);
            Cur := Start;
            <b>repeat
            </b>Cur := StrPos(Cur, PChar(SubStr));
            <b>if </b>Cur = <b>nil then </b>Break;
            ShowMessage(<font color="#0000FF">'FN ist ' </font>+ IntToStr(Cur - Start));
            Inc(Cur, Length(SubStr));
            <b>until </b>False;
            <b>end</b>;
            <br>
            Hagen
            </font>
            </code></pre&gt

            Comment


            • #7
              <pre>

              <code><font size=2 face="Courier New">Hier nochmal ein Code der das Extrahieren der Teilstrings demonstriert.
              <br>
              <b>var
              </b>Start,Cur,Next: PChar;
              <b>begin
              </b>AStr := <font color="#0000FF">'asfgDFAsdfafgDFAkljklöqDFAwqwer'</font>;
              Substr := <font color="#0000FF">'DFA'</font>;
              Start := PChar(AStr);
              Cur := Start;
              <b>repeat
              </b>Next := StrPos(Cur, PChar(SubStr));
              <b>if </b>Next = <b>nil then </b>Break;
              ShowMessage(<font color="#0000FF">'FN ist ' </font>+ IntToStr(Next - Start) + <font color="#0000FF">' und hat Länge ' </font>+ intToStr(Next - Cur));
              SetLength(PartialString, Next - Cur);
              Move(Cur^, Pointer(PartialStrign)^, Length(PartialString));
              Cur := Next + Length(SubStr);
              <b>until </b>False;
              <b>end</b>;
              <br>
              Hagen
              <br>
              </font>
              </code></pre&gt

              Comment


              • #8
                PChar's sind also eine feine Sache, wenn man weiß wie.<br>
                In der Borland Newsgroup gab's immer wieder Leute die meinten PChar's sollten wegrationalisert werden !<br>

                Da die einzelnen PChars = Pointer ja immer in den allozierten AStr zeigen müssen und dürfen diese NICHT freigegeben werden. Das ist auch der Grund warum gerade diese PChars so effizient sind, sie benötigen in diesem Beispiel keinerlei Allozierungen ersparen uns die vielen Kopier- und Reallozierungsaufrufe die notwendig wären mit String's.<br&gt

                Comment


                • #9
                  Danke für die Auskunft. Trotzdem habe ich noch eine Frage: gibt's über die Verwendung von PChar ausser für WinAPI-Funktionen irgendwo was Schriftliches? Die Hilfe ist da ziemlich dünn, auch Warken, Teixeira, Cantu halten sich ziemlich bedeckt..

                  Comment


                  • #10
                    Weiß ich nicht. Die Sache ist aber einfach. Ein PChar ist ein typisierter Pointer=Zeiger auf EIN Character = Zeichen. Es gelten die gleichen Regeln wie z.B. einem Zeiger auf ein Byte -> PByte. PChar ist der einzigst brauchbare Pointertyp mit dem man rechnen kann, heist auf die Zeigeradresse Offsets zu addieren oder subtrahieren. PChar Zeiger können direkt verglichen werden, dabe wird NICHT der referenzierte Inhalt des Zeigers verglichen sondern tatsächlich der Zeiger selber.<br>
                    Allg. gilt nun das ein PChar eine Zeiger auf nicht nur EIN Char sondern mehrere nachfolgende Zeichen sein kann. Ein solcher STRING muß mit einer NULL = #0 abgeschlossen sein, da man ja erkennen muß wo dieser PChar-String aufhört.<br>
                    Dadurch sind PChar's nicht so effizient in der Geschwindigkeit wie LongStrings.<br>
                    Sie sind aber die effizienteste Speicherform für lange Strings, da sie nur ein Zeichen=0 mehr benötigen als der informative String selber.<br>
                    Eine Kombination, wie oben gezeigt, von PChar-Arithmetik und LongString-Storage ist ideal, schnell, speichereffizient, dynamisch und flexibel.<br>
                    Die neuen LongString SIND PChars, eine LongString Variable IST ein Zeiger = PChar.<br> D.h. normalerweise kann eine LongString-Variable direkt in einen PChar Typ konvertiert werden, was keinerlei Geschwindigkeitverlust einbringt.<br>
                    PChar's müssen aber manuell alloziert werden falls die nötig ist. Diese hängt davon ab ob sie selber als Zeiger auf eine Storage oder aber nur als Referenz in einen schon allozierten Speicher dienen. Das ist so als ob Du ein Object erzeugst und dieses in 5 verschiedene Variablen speicherst. Über jede dieser Referenzen kann das Object angesprochen werden und auch zerstört werden.All anderen Referenzen werden dann natürlich ungültig.<br>
                    LongStrings sind da schon flexible da eben der Compiler und die RTL sich darum kümmert diesen zu allozieren und freizugeben.<br>
                    Allerdings ist die Manipulation dieser Strings in Delphi aufwendig, langsam, mit vielen Kopierfunktionen, Speicherzugriffen und Reallokationen verbunden. Das ist der Preis den man zahlt für den zusätzlichen Komfort.<br>

                    Jo, mehr fällt mir jetzt nicht ein :

                    Comment


                    • #11
                      Hallo Hagen,<br>
                      ein Problem habe ich noch: beim Testen mit deiner Funktion (Text Nr. 5 von 9) ist mir aufgefallen, dass es offenbar eine Größengrenze für PChar gibt. Wo sie genau liegt, kann ich nicht sagen (jedenfalls nicht bei 255 Zeichen); aber bei mehreren KB großen Textdateien wird in Cur := StrPos(Cur, PChar(SubStr)); if Cur = nil then Break; Cur immer auf nil gesetzt. Kennt du dieses Problem

                      Comment


                      • #12
                        Eine wichtige Korrektur: das Problem tritt nicht bei Textdateien > 1 KB auf, sondern bei anderen Dateitypen, z.b. tlb oder dll/exe. Bei letzteren wird z.B. der Dateianfang 'MZ' noch erkannt, spätere Zeichenfolgen wie 'Microsoft' nicht mehr

                        Comment


                        • #13
                          einfach, StrPOs() sucht nach dem SubStr <b>und</b> dem Zeichen #0. Dieses Zeichen ist das Terminierungszeichen für PChar's. Da PChars nicht wie Pascal String einen zusätzliches Längenfeld hat muß die Länge eines PChars anders beschrieben werden, eben durch eine Null am Ende des Strings. Nutzt Du nun binäre Daten wie EXE,DLL usw. dann können dort eben auch NULLEN vorkommen und somit die funktionsweise in Deinem Falle "stören". Alledings hättest Du gleich sagen können das Du auch binäre Daten durchsuchen möchtest. Ich glaube es gibt noch eine funktion StrLPos() oder ich habe ein solche mal selber geschrieben. Anstatt nun auch auf #0 zu scannen wird dieser Funktion der maximal Scanbereich, eg. Länge des PChars mit übergeben.

                          Gruß hage

                          Comment

                          Working...
                          X