hawkmaster: Textdatei in DB, bessere Lösung als mit RegEx?

Hallo zusammen,
Ich habe zwar eine Lösung mit Hilfe reulärer Ausdrücke gefunden.
mich würde einfach mal eure Meinung interessieren ob es vielleicht eine bessere oder einfachere Lösung gibt.

Folgendes:
Es gibt verschiedene Textdateien (eigentlich sind es Beschreibungs / Konfigurationsdateien)die jeweils mehrere 1000 Zeilen enthalten können.
Unter anderem gibt es viele Zeilen bzw. eine Rubrik die aufgebaut ist wie folgt:

*UIConstraints: *EFOutputBin Lower *EFPrintSize A6
*UIConstraints: *EFPrintSize A6 *EFOutputBin Lower
*UIConstraints: *EFOutputBin Lower *EFPrintSize A6.IMG-AREA.FullBleed
*UIConstraints: *EFPrintSize A6.IMG-AREA.FullBleed *EFOutputBin Lower
*UIConstraints: *EFDocServer *InputSlot Tray1
*UIConstraints: *InputSlot Tray1 *EFDocServer
*UIConstraints: *EFDuplex *EFMediaInterlv
*UIConstraints: *EFMediaInterlv *EFDuplex

Fester Bestandteil ist immer der Zeilen Beginn mit;
*UIConstraints:
Desweiteren gibt es immer zwei Optionen die immer mit * beginnen.
Danach kommt der dazugehörige Wert getrennt von Blanks.
Wie man aber an der letzten Zeile sieht kann es auch Zeilen geben die keine Werte haben.

Ich möchte die Zeilen wie folgt in einer DB speichern.

Option1        Wert1           Option2               Wert2
---------------------------------------------------------------------
EFOutputBin    Lower          EFPrintSize            A6

Wie gesagt habe ich eine Lösung mit Regulären Ausdrücken aber da eigentlich alle möglichen Zeichen vorkommen können, wird das ganze dadurch sehr erschwert.

Könnte man vielleicht auch die Zeilen mit "file()" in ein Array lesen und dann versuchen mit "explode" nach leerstellen die einzelnen Elemente herauszufiltern?

Mich würde einfach interessieren wie ihr Experten dies angehen würdet.

vielen Dank und viele Grüße
hawk

  1. Hallo,

    Wie gesagt habe ich eine Lösung mit Regulären Ausdrücken aber da eigentlich alle möglichen Zeichen vorkommen können, wird das ganze dadurch sehr erschwert.

    Könnte man vielleicht auch die Zeilen mit "file()" in ein Array lesen und dann versuchen mit "explode" nach leerstellen die einzelnen Elemente herauszufiltern?

    Naja, Du kannst das auch einfach per fgetcsv() einlesen und dem den Blank als Delimiter übergeben:

    $fp = fopen('datei', 'r');  
    while (($record = fgetcsv ($fp, 8192, ' ')) !== false) {  
      // Leerzeile oder ungültige Zeile (3 Eintäge mindestens)  
      if (count($record) <= 3) continue;  
      // Ersten Eintrag entfernen  
      $prefix = array_shift ($record);  
      // Ungültige Zeile  
      if ($prefix != '*UIConstraints:') {  
        continue;  
      }  
      // Hole option 1  
      $option1 = array_shift ($record);  
      if ($option1[0] != '*') {  
        continue; // Ungültig  
      }  
      $option1 = substr ($option1, 1); // * entfernen  
      // Hole option 2  
      $option2 = array_shift ($record);  
      if ($option2[0] != '*') {  
        // Ok, ist doch nicht Option 2, sondern Wert 1  
        $wert1 = $option2;  
        // Ungültig  
        if (!count ($record)) {  
          continue;  
        }  
        $option2 = array_shift ($record);  
        if ($option2[0] != '*') {  
          continue; // ungültig  
        }  
        $option2 = substr ($option2, 1); // * entfernen  
      } else {  
        $wert1 = NULL;  
        $option2 = substr ($option2, 1); // * entfernen  
      }  
      // Hole Wert 2  
      if (count ($record)) {  
        $wert2 = array_shift($record);  
      } else {  
        $wert2 = NULL;  
      }  
      // Ungültig  
      if (count ($record)) {  
        continue;  
      }  
      // Nun enthalten $option1, $wert1, $option2 und $wert2 die gewünschten  
      // Daten. $wert1 und $wert2 können NULL sein.  
      // Jetzt halt in die DB kloppen...  
    }  
    fclose ($fp);
    

    Man könnte hier vmtl. noch ein paar Dinge verbessern, aber in der Form sollte der Algorithmus sehr einfach zu verstehen sein.

    Darf ich übrigens mal fragen, was das für ein seltsames Dateiformat ist? ;-)

    Viele Grüße,
    Christian

    1. Hallo Christian,

      Naja, Du kannst das auch einfach per fgetcsv() einlesen und dem den Blank als Delimiter übergeben:

      Erst mal recht herzlichen Dank für deinen Tipp.
      Das ist in der Tat ein guter Ansatz. Ich werde das mal ausprobieren. event. ist dies auch einiges schneller als mit RegEx.

      Darf ich übrigens mal fragen, was das für ein seltsames Dateiformat ist? ;-)

      Natürlich darfst du.
      Es handelt sich um eine PostScript Drucker Beschreibungsdatei wie sie bei Windows aber auch Linux (Unix) verwendet wird.
      Es ist praktisch ein Standard und unterliegt einigen Spezifikationen. Das was ich gerade mache ist nur ein winziger Abschnitt davon. Er behandelt die "Ausnahmen" der Drucker Optionen, also Dinge die im User Interface nicht ausgewählt werden dürfen.
      Ich nehme an du kennst dich auch mit Linux / Unix aus. Hier werden diese Dateien auch schon lange verwendet. Unter anderem für CUPS.
      Ich mache seit einiger Zeit ein "Web FrontEnd" für solche Drucker für eine Intranetlösung.

      vielen Dank und viele Grüße
      hawk

  2. Fester Bestandteil ist immer der Zeilen Beginn mit;
    *UIConstraints:
    Desweiteren gibt es immer zwei Optionen die immer mit * beginnen.
    Danach kommt der dazugehörige Wert getrennt von Blanks.
    Wie man aber an der letzten Zeile sieht kann es auch Zeilen geben die keine Werte haben.

    Ich möchte die Zeilen wie folgt in einer DB speichern.

    Option1        Wert1           Option2               Wert2

    EFOutputBin    Lower          EFPrintSize            A6

    Wie gesagt habe ich eine Lösung mit Regulären Ausdrücken aber da eigentlich alle möglichen Zeichen vorkommen können, wird das ganze dadurch sehr erschwert.
    Könnte man vielleicht auch die Zeilen mit "file()" in ein Array lesen und dann versuchen mit "explode" nach leerstellen die einzelnen Elemente herauszufiltern?

    Mich würde einfach interessieren wie ihr Experten dies angehen würdet.

    hallo hawk
    Dein Problem ist das alte.
    Du hast im Thread weiter unten Daten gepostet, welche die Probleme klar machen. Warum machst du einen neuen Thread?

    Aus den Daten im alten Thread wird klar das explode auf Leerzeichen keine Universallösung sein kann.

    mfg Beat

    --
    Woran ich arbeite:
    X-Torah
       <°)))o><                      ><o(((°>o
    1. Hallo Beat,
      ja ich habe noch überlegt ob ich es im alten Thread posten soll, war mir aber unsicher ob da überhaupt jemand reinschaut bzw. ich dachte weil es ja eine Lösung sein soll OHNE RegEx.

      Entschuldige bitte falls das falsch war.

      Ich wollte dich eh auch fragen, ob du event. mit Perl das anders angehen würdest?

      vielen Dank und viele Grüße
      hawk

      1. ja ich habe noch überlegt ob ich es im alten Thread posten soll, war mir aber unsicher ob da überhaupt jemand reinschaut bzw. ich dachte weil es ja eine Lösung sein soll OHNE RegEx.
        ...
        Ich wollte dich eh auch fragen, ob du event. mit Perl das anders angehen würdest?

        Ich würde eine zweistufige RE verwenden.

        Christan Seilers Ansatz ist zwar einleuchtend, basiert aber noch auf mangelhaften Daten. So ist der Name deiner *Option variabel, und du musst zuerst die Syntax der Bausteine Option Variable und Parameter definieren.

        Was du machen kannst:
        Teste dein File, ob irgend etwas wie \S\\S vorkommt. Wenn solches nicht vorkommt, dann kannst du hoffen, dass dein Problem relativ einfach lösbar ist. Wenn aber \S\ vorkommt, dann ist bereits die Erkennung von Parametern schwierig. Ein Parameter muss dass \s\* voraussetzen.

        Mangelhaft finde ich, dass du uns nie über die Syntax des Files restlos aufklärst. Das wäre aber deine erste Aufgabe. und mit ein paar RE Abfragen kannst auch dokumentieren, auf was Verlass sein darf.

        mfg Beat

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

          Teste dein File, ob irgend etwas wie \S\\S vorkommt. Wenn solches nicht vorkommt, dann kannst du hoffen, dass dein Problem relativ einfach lösbar ist. Wenn aber \S\ vorkommt, dann ist bereits die Erkennung von Parametern schwierig. Ein Parameter muss dass \s\* voraussetzen.

          Ich habe eben mal mit einem erweiterten TextEditor nach \S\* gesucht. Es wurde nichts gefunden. Also könnte ich Glück haben :-)

          Mangelhaft finde ich, dass du uns nie über die Syntax des Files restlos aufklärst. Das wäre aber deine erste Aufgabe. und mit ein paar RE Abfragen kannst auch dokumentieren, auf was Verlass sein darf.

          Entschuldige bitte ich wollte nichts verschweigen. Ich weiss nur nicht welche Infos noch zusätzlich gut wären bzw. was du mit "Syntax des Files" meinst.

          Die Beispieldatei die ich gerade teste hat 4200 Zeilen, die kann ich ja nicht hier posten.

          vielen Dank und viele Grüße
          hawk

        2. Hallo Beat,

          ich möchte nochmals nachhaken damit ich es beim nächsten posten besser mache.
          Du meintest ja ich hätte die "Syntax des Files" nicht erklärt.
          Ich würde wirklich gerne wissen welche Informationen notwendig sind oder wie du das meinst?

          Ich würde eine zweistufige RE verwenden.

          Auch das würde mich interessieren wie du hier vorgehen würdest.

          vielen Dank und viele Grüße
          hawk

          1. ich möchte nochmals nachhaken damit ich es beim nächsten posten besser mache.
            Du meintest ja ich hätte die "Syntax des Files" nicht erklärt.
            Ich würde wirklich gerne wissen welche Informationen notwendig sind oder wie du das meinst?

            Du hast uns Kostproben des Files gezeigt und schnippsel deiner Format-Einsicht offenbart.
            Das ist keine Formatbeschreibung.

            Eine Bescheibung könnte lauten:

            ()?  = 0 oder 1 Vorkommen
            ()*  = 0 oder mehrere Vorkommen
            ()+  = 1 oder mehr Vorkommen
            ( | ) = alternative

            WS (= Whitespace) = ( "[\ \t]" )+
            LF (= Linefeed)   = "\n"
            MARK              = "*"
            NCH (Normalcharacter) = "[A-Za-z0-9]"
            NSC (NoMarkNoWhitespaceNoLinefeed-Character) = "[^*\s\n]"
            NLF (NoLinefeed-Charakter) = [^\n]
            OPT (Option)      = MARK (NCH)+
            PAR (Paramter)    = MARK (NCH)+
            VAL (Wert)        = NSC ( ( NLF )* NSC )?
                 Whitepsace und MARK können in VAL vorkommen,
                 aber nicht am Anfang oder Ende

            RECORD = OPT WS PAR (WS VAL)? ( WS PAR (WS VAL)? )? (WS)? LF
            FILE = ( RECORD | NONERECORD )+

            Auch wenn es keine Perl Syntax ist, ist das Format verständlich.
            Zumindest lässt sich daraus ein RE basteln.

            Ich würde eine zweistufige RE verwenden.

            Auch das würde mich interessieren wie du hier vorgehen würdest.

            Wenn ich mir bezüglich dem Format eines Files nicht sicher bin, schreibe ich mir ein Script, das mir erlaubt, das Format zu eruieren.
            Dazu ist es wichtig, zu erfahren, welche Zeilen zutreffen, und welche Zeilen nicht zutreffen, und ihr Format als Error auszugeben.

            Da * ein kritisches Zeichen ist, würde ich im File natürlich den Gebrauch dieses Zeichens eruieren. Desgleichen der Gebrauch von Whitespace.
            Wenn ich dann eine Syntax beschreiben kann, die alle Tests (auch absurde eigene Tests) besteht, kann ich hoffen, dass das Einlesen in die Datenbank funktionieren kann.

            mfg Beat

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

              vielen Dank nochmals für deine Mühe und Erklärung.
              Auch wenn ich nicht mit allem was anfangen kann und vor allem wie ich es in die Praxis umsetzen kann.

              Als relativer Anfänger mit regulären Ausdrücken ist es für mich schwierig so ein File anständig zu analysieren.
              Natürlich sehe ich "Halt" da ist ein * drin nachdem ich suchen muss und das der * ein Sonderzeichen ist das maskiert werden muss.
              Auch habe ich gesehen das z.b. im Suchmuster bzw. im Text die Zeichen + vorkommen können.

              Na mal sehen...

              vielen Dank und viele Grüße
              hawk