Tom: Regular Expressions

Hello,

in einem längeren Text befindet sich eine Startsignatur mehrfach und die Abschlusssignatur des gesuchten Bereiches nur einmal.

xxxxxxxxxxxxxxxx
    xxxxxxxxxxxxxSTARTxxxxxxxxxxxxxxx
    xxxSTARTxxxxxxxxxxx
    xxxxxxxxxxxxxxxxxxxxxxxx
    xxxxxxxxxxxxSTARTsssssssssss
    sssssssss
    ssssssssssssssSTOPxxxxxxx
    xxxxxxxxxxxxxxxxxx
    STARTxxxxxxxxxxxxxxxxxx
    xxxxxxxxxxxxxxxxxx

sss wird gesucht.

Wie muss ich das machen, dass ich nur den Bereich vom letzten Vorkommen von START vor STOP bis STOP bekomme?

Ich habe jetzt diverse Versuche mit Greedyness, Assertions usw. durch und komme auf keinen Lösungsweg.

Dabei kann ich die Positionen eindeutig identifiziern, könnte es also mit "Drumherumprogrammierung" auch lösen.

$_total_matches = array();
$offset = 0;
while (preg_match($pattern1, $content, $_matches, PREG_OFFSET_CAPTURE, $offset))
{
    $_lastmatch = end($_matches);
    $offset = $_lastmatch[1] + strlen($_lastmatch[0]);
    $_total_matches[] = $_lastmatch;
}

Ich würde nur gerne wissen, ob man für diesen Fall nicht doch eine Regular Expression finden kann.

Liebe Grüße aus dem schönen Oberharz

Tom vom Berg

--
Nur selber lernen macht schlau
http://bergpost.annerschbarrich.de
  1. Folgende regex (PCRE) sollte  es funktionieren. Hab ich auch getestet.

    START([^STAR]*)STOP

    START (sammle alle daten die nicht gleich der Startsequenz sind bis) STOP

    1. Hello,

      Folgende regex (PCRE) sollte  es funktionieren. Hab ich auch getestet.

      START([^STAR]*)STOP

      START (sammle alle daten die nicht gleich der Startsequenz sind bis) STOP

      Nur, dass [^STAR] eine Zeichenklasse darstellt, die alle _Zeichen_ akzeptiert, die nicht 'S' oder 'T' oder 'A' oder 'R' sind. Reihenfolge und Anzahl sind dabei vollkommen egal.

      'Finde nicht Zeichenkette' gibt es mWn auch nicht bei Regular Expressions.

      Liebe Grüße aus dem schönen Oberharz

      Tom vom Berg

      --
      Nur selber lernen macht schlau
      http://bergpost.annerschbarrich.de
  2. Hello Tom,

    in einem längeren Text befindet sich eine Startsignatur mehrfach und die Abschlusssignatur des gesuchten Bereiches nur einmal.

    xxxxxxxxxxxxxxxx
        xxxxxxxxxxxxxSTARTxxxxxxxxxxxxxxx
        xxxSTARTxxxxxxxxxxx
        xxxxxxxxxxxxxxxxxxxxxxxx
        xxxxxxxxxxxxSTARTsssssssssss
        sssssssss
        ssssssssssssssSTOPxxxxxxx
        xxxxxxxxxxxxxxxxxx
        STARTxxxxxxxxxxxxxxxxxx
        xxxxxxxxxxxxxxxxxx

    sss wird gesucht.

    Wie muss ich das machen, dass ich nur den Bereich vom letzten Vorkommen von START vor STOP bis STOP bekomme?

    Ich habe jetzt diverse Versuche mit Greedyness, Assertions usw. durch und komme auf keinen Lösungsweg.

    Dabei kann ich die Positionen eindeutig identifiziern, könnte es also mit "Drumherumprogrammierung" auch lösen.

    Willst du es jetzt unbedingt mit RegExp machen?

    Hier erschiene mir eine Lösung mit strpos(), strrpos() und substr() nämlich vermutlich viel einfacher.

    Gruß Gunther

    1. Hello,

      in einem längeren Text befindet sich eine Startsignatur mehrfach und die Abschlusssignatur des gesuchten Bereiches nur einmal.

      xxxxxxxxxxxxxxxx
          xxxxxxxxxxxxxSTARTxxxxxxxxxxxxxxx
          xxxSTARTxxxxxxxxxxx
          xxxxxxxxxxxxxxxxxxxxxxxx
          xxxxxxxxxxxxSTARTsssssssssss
          sssssssss
          ssssssssssssssSTOPxxxxxxx
          xxxxxxxxxxxxxxxxxx
          STARTxxxxxxxxxxxxxxxxxx
          xxxxxxxxxxxxxxxxxx

      sss wird gesucht.

      Wie muss ich das machen, dass ich nur den Bereich vom letzten Vorkommen von START vor STOP bis STOP bekomme?

      Ich habe jetzt diverse Versuche mit Greedyness, Assertions usw. durch und komme auf keinen Lösungsweg.

      Dabei kann ich die Positionen eindeutig identifiziern, könnte es also mit "Drumherumprogrammierung" auch lösen.
      Willst du es jetzt unbedingt mit RegExp machen?

      Ja. Wenn es geht, möchte ich gerne wissen, wie.

      Hier erschiene mir eine Lösung mit strpos(), strrpos() und substr() nämlich vermutlich viel einfacher.

      Wenn Du auf das Muster dort oben anspielst, das ist eben nur ein Muster.
      RegExp muss ich sowieso einsetzen. Wie oft die Startsequenz vorkommt weiß ich nicht, was x un s für Zeichen sind, weiß ich auch nicht vorher...

      Liebe Grüße aus dem schönen Oberharz

      Tom vom Berg

      --
      Nur selber lernen macht schlau
      http://bergpost.annerschbarrich.de
      1. Hello again,

        Ja. Wenn es geht, möchte ich gerne wissen, wie.

        Hier erschiene mir eine Lösung mit strpos(), strrpos() und substr() nämlich vermutlich viel einfacher.

        Wenn Du auf das Muster dort oben anspielst, das ist eben nur ein Muster.
        RegExp muss ich sowieso einsetzen. Wie oft die Startsequenz vorkommt weiß ich nicht, was x un s für Zeichen sind, weiß ich auch nicht vorher...

        ich bin leider alles andere als ein Profi in Sachen RegExp, aber vielleicht kommst du mit den Stichwörtern ja auch alleine weiter.

        Wenn dann würde ich mal annehmen, dass du hier

        • (?=...) positive lookahead
        • (?(condition)...|...) / (?(condition)...) if-then-else / if-then pattern
          verwenden musst, um dein gewünschtes Ziel zu erreichen.

        Hope it helps.

        Gruß Gunther

        1. Hello,

          • (?(condition)...|...) / (?(condition)...) if-then-else / if-then pattern

          Condition habe ich noch nicht untersucht, ob das helfen kann...

          Schau ich mir mal an

          Liebe Grüße aus dem schönen Oberharz

          Tom vom Berg

          --
          Nur selber lernen macht schlau
          http://bergpost.annerschbarrich.de
  3. (H[ae]llo|Hi(ho)|Nabend) Tom,

    xxxxxxxxxxxxxxxx
        xxxxxxxxxxxxxSTARTxxxxxxxxxxxxxxx
        xxxSTARTxxxxxxxxxxx
        xxxxxxxxxxxxxxxxxxxxxxxx
        xxxxxxxxxxxxSTARTsssssssssss
        sssssssss
        ssssssssssssssSTOPxxxxxxx
        xxxxxxxxxxxxxxxxxx
        STARTxxxxxxxxxxxxxxxxxx
        xxxxxxxxxxxxxxxxxx

    sss wird gesucht.

    Wie muss ich das machen, dass ich nur den Bereich vom letzten Vorkommen von START vor STOP bis STOP bekomme?

    Ist dir preg_match('/\A.+START(.+?)(?=STOP)/s', $content, $_matches) zu einfach?
    Das liefert in $_matches[1] den gewünschten Teilstring. Falls dir nicht gefällt, dass
    auch noch etwas mehr gefunden wird, nimmst du halt
    preg_replace('/\A.+START(.+?)(?=STOP).+\z/s', '$1', $content)

    Ich habe jetzt diverse Versuche mit Greedyness, Assertions usw. durch und komme auf keinen Lösungsweg.

    preg_match('/(?<=START)(.(?!START))+?(?=STOP)/s', $content, $_matches)
    schaut zwar nicht sehr elegant aus, liefert aber das gewünschte Ergebnis.

    Dabei kann ich die Positionen eindeutig identifiziern, könnte es also mit "Drumherumprogrammierung" auch lösen.

    Warum versuchst du es dann mit Regulären Ausdrücken?
    Soll das eine Knobelaufgabe werden? ;-)

    MffG
    EisFuX

    1. Nachtrag

      ... Falls dir nicht gefällt, dass
      auch noch etwas mehr gefunden wird, nimmst du halt
      preg_replace('/\A.+START(.+?)(?=STOP).+\z/s', '$1', $content)

      preg_replace('/\A.+START(.+?)STOP.+\z/s', '$1', $content)

      tut es natürlich auch, ganz ohne "komplizierte" Assertions
      (die einfachen "\A" und "\z" bleiben aber).

      MffG
      EisFuX

    2. Hello,

      Wie muss ich das machen, dass ich nur den Bereich vom letzten Vorkommen von START vor STOP bis STOP bekomme?

      Ist dir preg_match('/\A.+START(.+?)(?=STOP)/s', $content, $_matches) zu einfach?
      Das liefert in $_matches[1] den gewünschten Teilstring. Falls dir nicht gefällt, dass
      auch noch etwas mehr gefunden wird, nimmst du halt
      preg_replace('/\A.+START(.+?)(?=STOP).+\z/s', '$1', $content)

      Könntest Du bitte nochmal 'was zu \A und \z sagen.
      Ist das identisch mit ^ und $?

      bei PHP steht leider nur "The simple assertions coded as \b, \B, \A, \Z, \z, ^ and $ are described above" und above ist (noch) nichts zu finden. Liegt wohl am Umbau der Seiten.
      http://de2.php.net/manual/en/regexp.reference.assertions.php

      Und Wiki schweigt sich dazu ganz aus.
      http://de.wikipedia.org/wiki/Regulärer_Ausdruck

      Warum versuchst du es dann mit Regulären Ausdrücken?
      Soll das eine Knobelaufgabe werden? ;-)

      Nö, sollte es nicht, ist es aber inzwischen geworden.

      Es geht dann noch weiter. Block  (.+?) enthält jetzt mehrere Paare von Parametern, die ich eigentlich haben will.

      Mit Stringfunktionen, explode() und einfachen RegExp habe ich das Ergebnis ja schon, aber nun hat mich der Ehrgeiz gepackt, aus ca. 40 Zeilen Programm eine Zeile Pattern zu machen...

      Nachdem Du mir gezeigt hast, dass der erste Teil funktioniert, bin ich sicher, dass der zweite auch noch klappt :-)

      Liebe Grüße aus dem schönen Oberharz

      Tom vom Berg

      --
      Nur selber lernen macht schlau
      http://bergpost.annerschbarrich.de
      1. Hello,

        Könntest Du bitte nochmal 'was zu \A und \z sagen.
        Ist das identisch mit ^ und $?

        Ok, ich denke, ich hab's gefunden

        Soll eine Zeichenkette nur aus dem gesuchten Muster bestehen (und es nicht nur enthalten), so muss in den meisten Implementierungen explizit definiert werden, dass das Muster von Anfang (\A oder ^)1 bis zum Ende der Zeichenkette (\Z, \z oder $)1 reichen soll, ansonsten matcht zum Beispiel [0-9]{2,5} auch bei der Zeichenkette „1234507“ die Teilzeichenkette „12345“. Aus dem gleichen Grund würde bspw. a* immer matchen, da jeder String, selbst der leere „“, mind. 0-mal das Zeichen „a“ enthält. 1Die Zeichen ^ und $ matchen im multiline-Modus (d. i. wenn der m-Modifier gesetzt wird) auch Zeilenanfänge und -enden.

        Nur die weitere Zerlegung krieg ich noch nicht hin.

        Liebe Grüße aus dem schönen Oberharz

        Tom vom Berg

        --
        Nur selber lernen macht schlau
        http://bergpost.annerschbarrich.de
      2. (H[ae]llo|Hi(ho)?|Mahlzeit) Tom,

        Könntest Du bitte nochmal 'was zu \A und \z sagen.
        Ist das identisch mit ^ und $?

        Manchmal.
        \A und \z verankern ein Suchmuster immer jeweils am Anfang und am Ende der gesamten Zeichenkette.
        Die Bedeutung von ^ und $ als "Anker" hängt vom Multiline-Modifikator m ab. Der ist mir zu
        blöd, wenn ich Zeilenumbrüche erkennen will, verlasse ich mich lieber auf (\r\n|[\r\n]).

        bei PHP steht leider nur "The simple assertions coded as \b, \B, \A, \Z, \z, ^ and $ are described above" und above ist (noch) nichts zu finden. Liegt wohl am Umbau der Seiten.
        http://de2.php.net/manual/en/regexp.reference.assertions.php

        Letztendlich schreibt man dort nur von der offiziellen Dokumentation ab.
        Der passende Abschnitt für ^ und $ dürfte der hier sein:

        PCRE_MULTILINE

        By default, PCRE treats the subject string as consisting  of  a  single
               line  of characters (even if it actually contains newlines). The "start
               of line" metacharacter (^) matches only at the  start  of  the  string,
               while  the  "end  of line" metacharacter ($) matches only at the end of
               the string, or before a terminating newline (unless PCRE_DOLLAR_ENDONLY
               is set). This is the same as Perl.

        When  PCRE_MULTILINE  it  is set, the "start of line" and "end of line"
               constructs match immediately following or immediately  before  internal
               newlines  in  the  subject string, respectively, as well as at the very
               start and end. This is equivalent to Perl's /m option, and  it  can  be
               changed within a pattern by a (?m) option setting. If there are no new-
               lines in a subject string, or no occurrences of ^ or $  in  a  pattern,
               setting PCRE_MULTILINE has no effect.

        Und Wiki schweigt sich dazu ganz aus.
        http://de.wikipedia.org/wiki/Regulärer_Ausdruck

        Die Homepage auf pcre.org verweist explizit auf den PCRE-Artikel in der englischprachigen Wikipedia.
        Also würde ich lieber da nachschauen.

        MffG
        EisFuX