hawkmaster: Suchmuster anpassen (preg_match)

Hallo zusammen,

ich suche in einer textdatei nach folgenden Zeilen.

*Option: *XYSeparations True *XYCompOverprint True

Das mache ich mit folendem Suchmuster:
if (preg_match_all("#\Option: \(.*?) (.*?) \*(.*?) (.*?)\n#s", $string1, $contents)){

Ich habe also nachher als Ergebnis
XYSeparations mit dem Wert "True" und
XYCompOverprint mit dem Wert "True"

Jetzt gibt es aber auch Zeilen die gar keine Werte haben. Wie etwa;

*Option: *XYCreateMaster *XYMMInUse

Jetzt greift mein Suchmuster nicht mehr.
ich habe schon einiges probiert, komme aber nicht auf die Lösung.
Wie kann man es erreichen das beide Varianten gefunden werden?

vielen Dank und viele Grüße
hawk

  1. Jetzt gibt es aber auch Zeilen die gar keine Werte haben. Wie etwa;

    *Option: *XYCreateMaster *XYMMInUse

    Jetzt greift mein Suchmuster nicht mehr.
    ich habe schon einiges probiert, komme aber nicht auf die Lösung.
    Wie kann man es erreichen das beide Varianten gefunden werden?

    Du kennst du Bedeutung von:
            (?:.+)?
    ???

    mfg Beat

    --
    Woran ich arbeite:
    X-Torah
       <°)))o><                      ><o(((°>o
    1. Hallo Beat,

      Du kennst du Bedeutung von:
              (?:.+)?
      ???

      vielen Dank für deine Hilfe,
      nein das kenne ich nicht.

      Weisst du irgendwie ist das frustrierend. Ich glaube ich bin zu blöd für reguläre Ausdrücke. So einfache Sachen bekomme ich noch hin, wenn es aber dann
      kompliziert wird muss ich passen.

      Ich habe schon den ganzen Morgen so viel probiert z.b. mit
      if (preg_match_all("#\Option: \(.*?)[ ]* (.*?)\*(.*?)[ ]* (.*?)\n#s", $string1, $contents)){

      Ich dachte mit [ ]* kann ich erreichen das die Leerstelle erkannt wird.

      wo müsste ich denn dein Beispiel einsetzen?

      vielen Dank und viele Grüße
      hawk

      1. Du kennst du Bedeutung von:
                (?:.+)?
        ???
        vielen Dank für deine Hilfe,
        nein das kenne ich nicht.

        (?:) ist eine non capturing Klammer, wird also nicht in $1 ... gespeichert.

        wo müsste ich denn dein Beispiel einsetzen?

        $string = "*Option  *aaa   bbb  *cccc  dd\n"
        /\Option:\s+\(\S+)(?:\s+(\S+))?\s+\*(\S+)(?:\s+(\S+))?\n/

        Keine Ahnung, ob \s \S hier hinreichend unterscheiden.

        mfg Beat

        --
        Woran ich arbeite:
        X-Torah
        ><o(((°>      ><o(((°>
           <°)))o><                      ><o(((°>o
        1. Hallo Beat,

          (?:) ist eine non capturing Klammer, wird also nicht in $1 ... gespeichert.

          hmm, also ich habe mal in meinem Büchlein für RegEx nachgeschaut.
          da gibt es etwas wie:
          (?:...)
          das heisst dann Submuster gruppieren aber keine Subtreffer festhalten.

          Nun sagt mir das leider nicht so viel.
          Also ich versuche mal dein Suchmuster zu verstehen :-) puhh

          \s+ bedeutet Whitespace Zeichen also Leerzeichen kann einmal oder mehrmals vorkommen ?

          \*(\S+)(?:\s+(\S+))?\s+
          Nach dem * dürfen nur "normale" Zeichen vorkommen ... ne da komme ich nicht mit ...

          vielen Dank und viele Grüße
          hawk

          1. (?:) ist eine non capturing Klammer, wird also nicht in $1 ... gespeichert.
            hmm, also ich habe mal in meinem Büchlein für RegEx nachgeschaut.
            da gibt es etwas wie:
            (?:...)
            das heisst dann Submuster gruppieren aber keine Subtreffer festhalten.

            und das
            (?:a(b))?
            finde 'ab' 0 oder 1 mal aber speichere nur b

            \s+ bedeutet Whitespace Zeichen also Leerzeichen kann einmal oder mehrmals vorkommen ?

            \*(\S+)(?:\s+(\S+))?\s+
            Nach dem * dürfen nur "normale" Zeichen vorkommen ... ne da komme ich nicht mit ...

            \S ist die Negation von \s, also Non-Whitespace-Charakters

            Das Problem in meinem Aufbau ist, dass ich nicht weiss ob du whitespace in Parametern oder Werten erlaubst, oder ob sie verlässlich nur die Tokens unterscheiden.

            mfg Beat

            --
            Woran ich arbeite:
            X-Torah
            ><o(((°>      ><o(((°>
               <°)))o><                      ><o(((°>o
            1. Hi Beat,
              vielen Dank nochmals für die erklärung und Hilfe.
              Ein wenig klarer ist es geworden.

              Das Problem in meinem Aufbau ist, dass ich nicht weiss ob du whitespace in Parametern oder Werten erlaubst, oder ob sie verlässlich nur die Tokens unterscheiden.

              hmm, also ich versuche es nochmals anders zu beschreiben was ich machen will.
              Eine Textdatei sieht wie folgt aus:

              *UIConstraints: *EFDuplex TopTop *EFInterlvTray HighCapacityInputBin1
              *UIConstraints: *EFInterlvTray HighCapacityInputBin1 *EFDuplex TopTop
              *UIConstraints: *EFDuplex *EFMediaInterlv
              *UIConstraints: *EFMediaInterlv *EFDuplex
              *UIConstraints: *EFDocServer True *InputSlot Tray1
              *UIConstraints: *InputSlot Tray1 *EFDocServer True
              *UIConstraints: *EFDocServer True *InputSlot Tray2
              *UIConstraints: *InputSlot Tray2 *EFDocServer True
              *UIConstraints: *EFDocServer True *InputSlot Tray3
              *UIConstraints: *InputSlot Tray3 *EFDocServer True
              *UIConstraints: *EFFold *EFMediaType Bond
              *UIConstraints: *EFFold ZfoldBottom *EFPageDelivery

              Ich möchte das alles in einer Datenbank speichern und zwar so am Beispiel Zeile 1.

              Option1 Wert1 Option2 Wert2
              -------------------------------------------------------------
              EFDuplex TopTop EFInterlvTray HighCapacityInputBin1

              Das klappt ja soweit mit meinem alten Suchmuster. Nur jetzt ist ein Problem aufgetaucht z.b. mit Zeile 3;

              *UIConstraints: *EFDuplex *EFMediaInterlv

              wo gar keine Werte für beide Optionen da sind oder auch wo nur ein Wert vorhanden ist wie in den beiden letzten Zeilen.

              Ich würde gerne in diesem Fall wenn kein Wert da ist, einfach ein Blank in dei DB schreiben also etwa:
              Option1 Wert1 Option2 Wert2
              -------------------------------------------------------------
              EFDuplex      EFMediaInterlv

              vielen Dank und viele Grüße
              hawk

        2. Hallo Beat

          /\Option:\s+\(\S+)(?:\s+(\S+))?\s+\*(\S+)(?:\s+(\S+))?\n/

          Ich habe es mal so eingesetzt aber so wird garnichts gefunden.

          hmm, wäre es vielleicht besser wenn ich zwei unterschiedliche Regex mache?
          Einer der immer nur dieses Konstrukt findet.
          *Option: *XYDuplex Tackjop *XYInterl HighBin

          und dann noch ein zweites das nur sowas findet:
          *Option: *XYDuplex *XYInterl

          was meinst du?

          vielen Dank und viele Grüße
          hawk

          1. /\Option:\s+\(\S+)(?:\s+(\S+))?\s+\*(\S+)(?:\s+(\S+))?\n/

            Ich habe es mal so eingesetzt aber so wird garnichts gefunden.

            wohl die \n am Schluss

            hmm, wäre es vielleicht besser wenn ich zwei unterschiedliche Regex mache?
            Einer der immer nur dieses Konstrukt findet.
            *Option: *XYDuplex Tackjop *XYInterl HighBin

            und dann noch ein zweites das nur sowas findet:
            *Option: *XYDuplex *XYInterl

            was meinst du?

            vielen Dank und viele Grüße
            hawk

            Ich schreibe Perl

            Offenbar war die newline am Ende zu viel.

              
            #!C:/Programme/Perl/bin/perl.exe -w  
            #  
            use strict;  
            BEGIN {  
             use CGI::Carp qw(carpout);  
             open(LOG, ">>error.txt")  or  die "Unable to append to error.txt: $!\n";  
             carpout(*LOG);  
            }  
              
            # my $s="*Opt:  *ABC def  *GHI  jkl  ";  
            my $s="*Opt:  *ABC  *GHI   ";  
              
            $s =~ / \*Opt:  
              \s+\*(\S+)  
              (?:\s+(\S+))?  
              \s+\*(\S+)  
              (?:\s+(\S+))?  
             /x  
             and  
             print $1, '=',$2 || '', '---' , $3,'=',$4 || '', "\n";  
              
            sleep(10);  
            
            

            Dies druckt das erwünschte aus.
            Protieren musst du selbst nach php
            die RE komprimiert:

            /\Option:\s+\(\S+)(?:\s+(\S+))?\s+\*(\S+)(?:\s+(\S+))?/

            mfg Beat

            --
            Woran ich arbeite:
            X-Torah
            ><o(((°>       ><o(((°>
               <°)))o><                      ><o(((°>o
            1. klappt leider noch nicht ganz,

              und zwar geht das Suchmuster irgendwie über die zeile hinaus:

              Als Beispiel die Textdatei mit:
              *UIConstraints: *EFDuplex TopTop *EFInterlvTray HighCapacityInputBin1
              *UIConstraints: *EFInterlvTray HighCapacityInputBin1 *EFDuplex TopTop
              *UIConstraints: *EFDuplex *EFMediaInterlv
              *UIConstraints: *EFMediaInterlv *EFDuplex
              *UIConstraints: *EFDuplex TopBottom *EFMediaType Heavy2
              *UIConstraints: *EFMediaType Heavy2 *EFDuplex TopBottom
              *UIConstraints: *EFDuplex TopBottom *EFMediaType Labels
              *UIConstraints: *EFMediaType Labels *EFDuplex TopBottom
              *UIConstraints: *EFDocServer True *InputSlot Tray1
              *UIConstraints: *InputSlot Tray1 *EFDocServer True
              *UIConstraints: *EFDocServer True *InputSlot Tray2
              *UIConstraints: *InputSlot Tray2 *EFDocServer True
              *UIConstraints: *EFDocServer True *InputSlot Tray3
              *UIConstraints: *InputSlot Tray3 *EFDocServer True
              *UIConstraints: *EFFold *EFMediaType Bond
              *UIConstraints: *EFFold ZfoldBottom *EFPageDelivery

              ab Zeile 3 also die zeile ohne werte sieht das Ergebnis dann so aus:

              Es gibt EFDuplex mit *EFMediaInterlv -- UIConstraints: mit *EFMediaInterlv

              Ich habe es so versucht:
              if (preg_match_all("#\UIConstraints:\s+\(\S+)(?:\s+(\S+))?\s+\*(\S+)(?:\s+(\S+))?#", $string1, $contents)){

              vielen Dank und viele Grüße
              hawk

              1. und zwar geht das Suchmuster irgendwie über die zeile hinaus:
                Als Beispiel die Textdatei mit:
                *UIConstraints: *EFDuplex TopTop *EFInterlvTray HighCapacityInputBin1
                *UIConstraints: *EFInterlvTray HighCapacityInputBin1 *EFDuplex TopTop
                *UIConstraints: *EFDuplex *EFMediaInterlv
                *UIConstraints: *EFFold *EFMediaType Bond
                *UIConstraints: *EFFold ZfoldBottom *EFPageDelivery

                ab Zeile 3 also die zeile ohne werte sieht das Ergebnis dann so aus:

                Ich habe es so versucht:
                if (preg_match_all("#\UIConstraints:\s+\(\S+)(?:\s+(\S+))?\s+\*(\S+)(?:\s+(\S+))?#", $string1, $contents)){

                Dann müssen wir halt noch spezifischer sein.
                Dort wo \S+ steht, müssen wir jetzt effektiv [A-Za-z]+ einsetzen um zwischen Werten und Parametern zu unterscheiden.

                /\Opt:\s+\([A-Za-z]+)(?:\s+([A-Za-z]+))?(?:\s+\*([A-Za-z]+)(?:\s+([A-Za-z]+))?)?/

                mfg Beat

                --
                Woran ich arbeite:
                X-Torah
                   <°)))o><                      ><o(((°>o
                1. Hallo Beat,

                  es gab noch ein kleines Problem weil auch Zahlen vorkommen können. Ich habe es aber lösen können indem ich noch zusätzlich 0-9 eingefügt habe.
                  Ich hoffe es ist richtig.

                  \s+\([A-Za-z0-9]+)(?:\s+([A-Za-z0-9]+))?(?:\s+\([A-Za-z0-9]+)(?:\s+([A-Za-z0-9]+))?)?

                  Jetzt scheint es zu funktionieren.
                  Ich muss aber ehrlich gestehen das ich das nie alleine hinbekommen hätte
                  und das ich das immer noch nicht ganz kapiert habe mit dem
                  (?:..)?

                  aber ich werde es nochmals durchgehen.

                  recht herzlichen Dank nochmals für deine Mühe und Geduld.

                  PS:
                  Ich habe mal parallel versucht ein einfaches Suchmuster hinzubekommen das wirklich nur diese Zeilen finden würde:
                  *UIConstraints: *EFFinisher *EFPunchOpt

                  if (preg_match_all("#\UIConstraints: \(.*?)[ ]?\*(.*?)\n#", $string1, $contents)){

                  ich dachte mit [ ]? kann man sagen: Es darf nur ein Leerzeichen vorkommen zwischen \* und \*
                  Aber es wird auch folgendes gefunden:
                  *UIConstraints: *EFFinisher False *EFPunchOpt 3Even

                  na egal, deine Syntax funktioniert ja.
                  vielen Dank und viele Grüße
                  hawk

                2. Hallo nochmals,

                  Dann müssen wir halt noch spezifischer sein.
                  Dort wo \S+ steht, müssen wir jetzt effektiv [A-Za-z]+ einsetzen um zwischen Werten und Parametern zu unterscheiden.
                  /\Opt:\s+\([A-Za-z]+)(?:\s+([A-Za-z]+))?(?:\s+\*([A-Za-z]+)(?:\s+([A-Za-z]+))?)?/

                  hmm, wenn ich mir so die verschiedenen Textdateien anschaue kann es auch sein das die Optionen und Werte alle möglichen Zeichen enthalten können.

                  *UIConstraints: *EFDocServer 0,37 *InputSlot Tray1
                  *UIConstraints: *InputSlot +1.5 *EFDocServer OK (Yes)
                  *UIConstraints: *EFDocServer High&Low *InputSlot 100%

                  ich vermute mal das es dann mit
                  [A-Za-z0-9] nicht mehr klappt oder ?

                  vielen Dank und viele Grüße
                  hawk

                  1. hmm, wenn ich mir so die verschiedenen Textdateien anschaue kann es auch sein das die Optionen und Werte alle möglichen Zeichen enthalten können.

                    *UIConstraints: *EFDocServer 0,37 *InputSlot Tray1
                    *UIConstraints: *InputSlot +1.5 *EFDocServer OK (Yes)
                    *UIConstraints: *EFDocServer High&Low *InputSlot 100%

                    ich vermute mal das es dann mit
                    [A-Za-z0-9] nicht mehr klappt oder ?

                    Offenbar eine Zeichensalat-Datenbank.

                    Ich bastle zuerst qr Tokens in perl

                    my $option = qr/\[A-Za-z]+:/;    # das optionslabel
                    my $sep = qr/\s+/;                # Separator
                    my £par = qr/\
                    ([A-Za-z0-9]+)/;   # Parameter
                    my $val = qr/(^*\s?)/;
                                                      # Value darf kein * enthalten
                                                      # darf nicht mit \s beginnen oder enden

                    /$option$sep$par(?:$sep$val)?(?:$sep$par(?:$sep$val)?)?/

                    gänzlich ungetestet.

                    mfg Beat

                    --
                    Woran ich arbeite:
                    X-Torah
                       <°)))o><                      ><o(((°>o
                    1. Hallo Beat,

                      Offenbar eine Zeichensalat-Datenbank.

                      ja so ähnlich kann man es echt sehen.

                      Ich bastle zuerst qr Tokens in perl

                      my $option = qr/\[A-Za-z]+:/;    # das optionslabel
                      my $sep = qr/\s+/;                # Separator
                      my £par = qr/\
                      ([A-Za-z0-9]+)/;   # Parameter
                      my $val = qr/(^*\s?)/;
                                                        # Value darf kein * enthalten
                                                        # darf nicht mit \s beginnen oder enden

                      /$option$sep$par(?:$sep$val)?(?:$sep$par(?:$sep$val)?)?/

                      ich werde das mal morgen versuchen in PHP nachzubauen.
                      herzlichen Dank nochmals.

                      vielen Dank und viele Grüße
                      hawk