hawkmaster: Hilfe bei regulärem Ausdruck gesucht

Hallo zusammen,

ich versuche mit PHP eine Textdatei nach bestimmten Vorkommen zu durchsuchen.
Die Suche geht immer über mehrere Zeilen.
Gesucht wird alle Vorkommen wo das wort "*OpenUI" am Zeilenanfang vorkommt. Danach kommt ein (oder mehrere) Leerzeichen gefolgt von * und dem Elementnamen.
Den Elementnamen habe ich.
Im Beispiel wird also alles gesucht das zwischen *OpenUI *PageSize: und
*CloseUI: *PageSize steht. Danach kommt eine Leerzeile und es folgt eine neue Zeile mit *OpenUI.

*OpenUI *PageSize: PickOne
*OrderDependency: 16.0 DocumentSetup *PageSize
*DefaultPageSize: Letter
*PageSize Letter/Letter: "(PageSize)(Letter)KDDHVDct/KFSet get exec countdictstack [{[612 792] KDDHVDct/_PGSize get exec} KDDHVDct/KFC get exec"
*PageSize Legal/Legal: "(PageSize)(Legal)KDDHVDct/KFSet get exec countdictstack [{[612 1008] KDDHVDct/_PGSize get exec} KDDHVDct/KFC get exec"
*PageSize Tabloid/Tabloid: "(PageSize)(Tabloid)KDDHVDct/KFSet get exec countdictstack [{[792 1224] KDDHVDct/_PGSize get exec} KDDHVDct/KFC get exec"
*PageSize A4/A4: "(PageSize)(A4)KDDHVDct/KFSet get exec countdictstack [{[595 842] KDDHVDct/_PGSize get exec} KDDHVDct/KFC get exec"
*CloseUI: *PageSize

*OpenUI *PageRegion: PickOne
...

Ich habe es so versucht.

  
if (preg_match_all("#\*OpenUI[^ ]* \*" .$element. "(/(.*?):|:)(.*?)\*CloseUI[^ ]*: \*" .$element. "#s", $teile[1], $contents)){  

Das funktionierte bisher ganz gut. Nun habe ich aber eine Testdatei bekommen in der *OpenUI nicht am Zeilenanfang steht und es als Kommentar mitten im Text steht.
z.b.

*% default charge numbers by following the steps below.
*% 1. Locate the line beginning with "*% *OpenUI *NIS63ChargeNumber".
*% 2. Remove the *% symbols and the following space from this line and all of the
*% lines, down to and including the line beginning with "*% *CloseUI:".
*% Your default charge numbers are now None and 123456789.
*% 3. Save the edited file.

Das heisst meine Suche findet auch;
*OpenUI *NIS63ChargeNumber".
*% 2. Remove the *% symbols and the following space from this line and all of the
*% lines, down to and including the line beginning with "*% *CloseUI:

Ich hatte folgendes versucht:
1. Mit ^ ganz am Anfang  #^\*OpenUI

2, Dann hatte ich versucht ganz am Ende ein Zeilenende mitzugeben
"\r\n#s"

Das alles brachte nichts. Was micht wundert ist auch die Tatsache das nur bis zum nächsten *CloseUI gesucht wird und nicht wie gedacht *CloseUI: *NIS66OpMsg

--------------------------------
*% *OpenUI *NIS66OpMsg/Operator Message: PickOne
*% *DefaultNIS66OpMsg: None
*% *OrderDependency: 56.0 DocumentSetup *NIS66OpMsg
*% *NIS66OpMsg None/None: "
*% (OpMsg)(***No Operator Message***)KDDHVDct/KFSet get exec
*% countdictstack [{}KDDHVDct/KFC get exec"
*% *End
*% *NIS66OpMsg OpMsg1/Message: "
*% (OpMsg)(Message)KDDHVDct/KFSet get exec
*% countdictstack [{(Message)KDDHVDct/KDOpMsg get exec}KDDHVDct/KFC get exec"
*% *End
*% *CloseUI: *NIS66OpMsg
------------------------------------

ein print_r($content) bringt unter anderem:
---------------
Array ( [0] => Array ( [0] => *OpenUI *NIS66OpMsg/Operator Message: PickOne *% *DefaultNIS66OpMsg: None *% *OrderDependency: 56.0 DocumentSetup *NIS66OpMsg *% *NIS66OpMsg None/None: " *% (OpMsg)(***No Operator Message***)KDDHVDct/KFSet get exec *% countdictstack [{}KDDHVDct/KFC get exec" *% *End *% *NIS66OpMsg OpMsg1/Message: " *% (OpMsg)(Message)KDDHVDct/KFSet get exec *% countdictstack [{(Message)KDDHVDct/KDOpMsg get exec}KDDHVDct/KFC get exec" *% *End *% *CloseUI: *NIS66OpMsg ) [1] => Array ( [0] => /Operator Message: ) [2] => Array ( [0] => Operator Message ) [3] => Array ( [0] => PickOne *% *DefaultNIS66OpMsg: None *% *OrderDependency: 56.0 DocumentSetup *NIS66OpMsg *% *NIS66OpMsg None/None: " *% (OpMsg)(***No Operator Message***)KDDHVDct/KFSet get exec *% countdictstack [{}KDDHVDct/KFC get exec" *% *End *% *NIS66OpMsg OpMsg1/Message: " *% (OpMsg)(Message)KDDHVDct/KFSet get exec *% countdictstack [{(Message)KDDHVDct/KDOpMsg get exec}KDDHVDct/KFC get exec" *% *End *% ) )
-----------------

Puuuhhh, ich glaube ich kapier die RegEx nie ;-(

vielen Dank und viele Grüße
hawk

  1. [^ ]*

    Du negierst die Leerzeichen in der Zeichenklasse?!

    Weiter habe ich noch nicht gesucht.

    1. Weiter habe ich noch nicht gesucht.

      Da ist noch mehr.

      Gesucht wird alle Vorkommen wo das wort "*OpenUI" am Zeilenanfang vorkommt.

      Der Zeilenanfang ist nicht im Suchmuster, was aber vielleicht gut so ist.

      Danach kommt ein (oder mehrere) Leerzeichen gefolgt von * und dem Elementnamen.

      Du suchst aber nach beliebig vielen, also auch keinen, Nicht-Leerzeichen, gefolgt von * und einem Leerzeichen.

      Danach wird es etwas undurchsichtig für mich.

    2. Hallo,
      danke für deine Hilfe.

      Du negierst die Leerzeichen in der Zeichenklasse?!

      Ja, ich kann dir aber ehrlich nicht mehr sagen warum ich das damals so gemacht hatte. Es gab irgend eine Situation wo mehrere Leerzeichen vorkamen.
      Ist schon eine weile her. Das dürfte aber nicht das Problem sein.

      vielen Dank und viele Grüße
      hawk

      1. Du negierst die Leerzeichen in der Zeichenklasse?!

        Ja, ich kann dir aber ehrlich nicht mehr sagen warum ich das damals so gemacht hatte. Es gab irgend eine Situation wo mehrere Leerzeichen vorkamen.
        Das dürfte aber nicht das Problem sein.

        Du willst nach Leerzeichen suchen und suchst nach Zeichen die keine Leerzeichen sind (die Menge ist dabei irrelevant). Ein Tip: Verabschiede dich von regulären Ausdrücken wenn Du der Meinung bist, daß das nicht das Problem sein dürfte, besonders dann, wenn es tatsächlich nicht das Problem in dem Sinne ist, daß es auch mit der Negation "funktioniert".

  2. if (preg_match_all("#\OpenUI[^ ]* \" .$element. "(/(.*?):|:)(.*?)\CloseUI[^ ]*: \" .$element. "#s", $teile[1],  $contents)){

    Dein Pattern ist reichlich wirr
    z.B. das subpattern "[^ ]* \*"

    Lerne bitte solche Dinge wie [ ]+
    oder wohl angemessener \s+

    Das alles brachte nichts. Was micht wundert ist auch die Tatsache das nur bis zum nächsten *CloseUI gesucht wird und nicht wie gedacht *CloseUI: *NIS66OpMsg

    Solange $element == '' wundert das auch nicht.

    Ich weiss PHP und REX sind eine unheilige Allianz, geprägt von unlesbaren Bandwürmern.

    Hier eine Perl REX

    my $element = 'example';  
    if($element){  
      my $start = qr/ ^ \*OpenUI \s+ \Q $element \E /x;  
      my $end = qr/ \*CloseUI \s+ \Q $element \E /x;  
      $test =~ /$start  \s+ (.+?) \s+ $end/xs  
           and subparse($element, $1);  
    }
    

    Was ich grundsätzlich tue:
    Ich definiere Start und Endpattern gesondert
    Beachte \Q ... \E, welches Spezielle Zeichen in $element behandelt.
    Das solltest du auch in PHP analog beachten.
    //x erlaubt mir, den String etwas zu strukturieren.

    mfg Beat

    --
    ><o(((°>           ><o(((°>
       <°)))o><                     ><o(((°>o
    Der Valigator leibt diese Fische
    1. Hallo Beat,
      auch dir vielen Dank für die Hilfe.

      Dein Pattern ist reichlich wirr
      z.B. das subpattern "[^ ]* \*"

      Ja ich weiss. Mir ist es selbst nicht mehr recht verständlich warum ich das damals so gemacht hatte.

      Solange $element == '' wundert das auch nicht.

      Wie kommst du darauf das $element leer ist? Dann würde ich es auch verstehen.

      Hier eine Perl REX
      Was ich grundsätzlich tue:
      Ich definiere Start und Endpattern gesondert
      Beachte \Q ... \E, welches Spezielle Zeichen in $element behandelt.

      Ich tue mir ein wenig schwer dein Perl Code in PHP umzusetzen. Aber ich versuche mal auch ein separates Start- und End- Suchmuster zu setzen.

      vielen Dank und viele Grüße
      hawk

    2. Hallo nochmals,

      Ich versuche jetzt gerade mal so wie in deinem Perl Beispiel einen Startpunkt und Endpunkt zu suchen.
      Nur mal die Suche nach *OpenUI am Zeilenanfang.
      *OpenUI *InputSlot: PickOne

      So, also mit ^ davor geht nicht.
      if (preg_match_all("#^\OpenUI \(.*?)#", $teile[1], $uielements)){

      hingegegen würde,
      if (preg_match_all("#\OpenUI \(.*?)\r#", $teile[1], $uielements)){
      funktionieren, aber dann hätte man das Problem mit dem Zeilenanfang nicht gelöst.
      Warum klappt das mit ^ nicht?

      vielen Dank und viele Grüße
      hawk

      1. So, also mit ^ davor geht nicht.
        if (preg_match_all("#^\OpenUI \(.*?)#", $teile[1], $uielements)){

        hingegegen würde,
        if (preg_match_all("#\OpenUI \(.*?)\r#", $teile[1], $uielements)){
        funktionieren, aber dann hätte man das Problem mit dem Zeilenanfang nicht gelöst.
        Warum klappt das mit ^ nicht?

        Zeilenenden sind Betriebssystemabhängig \n, \r oder \r\n
        Konvertiere die Zeilenenden des Quellfiles in die Form, welche der Vorstellung des Interpreters von Zeilenende entspricht.

        mfg Beat

        --
        ><o(((°>           ><o(((°>
           <°)))o><                     ><o(((°>o
        Der Valigator leibt diese Fische