Robert R.: Pattern für preg_match

Liebe Mitdenker,
liebe Wissende,
liebe Neugierige,

ja!

ich bekomme das Pattern nicht hin, dass ich für die Zerlegung des Type-Elemments von

[3] => Array
        (
            [Field] => class
            [Type] => set('Hotel','Pension','Lodge','Ferienhaus','Ferienwohnung')
            [Null] => YES
            [Key] =>
            [Default] =>
            [Extra] =>

benötige. Wenn nur dec(10,2) oder int(11) oder so drinsteht, klappt alles. Aber die Strings mit dem Apostroph bekomme ich einfach nicht in die Finger... Da matcht dann gar nichts mehr.

Ich habe das schon total verkürzt in der Funktion:

$pm = preg_match('~([a-z]+)((['a-z,0-9]*))~', $columns['Type'], $matches);

return $matches;

Ich will im ersten Schritt nur den Typbezeichner und die Spezifikation auseinander klamüsern.

Spirituelle Grüße
Euer Robert

--
Möge der Forumsgeist wiederbelebt werden!
  1. Hakuna matata!

    [Field] => class
                [Type] => set('Hotel','Pension','Lodge','Ferienhaus','Ferienwohnung')
                [Null] => YES
                [Key] =>
                [Default] =>
                [Extra] =>

    Das sieht für mich nach einer Datenbank-Abstraktionsschicht aus, stimmt das? Wenn ja, dann gibt es vielleicht in der Bibliothek schon einen Parser für das Type-Feld, welche Bibliothek benutzt du denn?

    $pm = preg_match('~([a-z]+)((['a-z,0-9]*))~', $columns['Type'], $matches);

    Ich glaube das Komma muss an dieser Stelle maskiert werden, auch wenn es dort kein Sonderzeichen ist. Außerdem möchtest du in der Zeichenklasse sicher auch Großbuchstaben und Umlaute zulassen.

    Ich glaube aber nicht, dass du mit einem Parser auf Basis von regulären Ausdrücken hundertprozentige Korrektheit erreichen wirst, denn in SQL-Strings sind auch wieder Hochkommata und schließende Klammern erlaubt, die bei der Kodierung in obiges Format wieder entsprechend maskiert werden würden. Ich würde daher zu einem Parser auf Basis eines endlichen Automaten raten, die sind soweit entwickelt, dass sie sogar autoamtisch aus einer kontextfreien Grammatik generiert werden können. Die Grammatik kannst für die obige Kodierung kannst du sicher irgendwo im SQL-Standard finden. Oder du greifst natürlich gleich zu einem fertigen SQL-Parser.

    --
    “All right, then, I'll go to hell.” – Huck Finn
    1. Tach!

      $pm = preg_match('~([a-z]+)((['a-z,0-9]*))~', $columns['Type'], $matches);
      Ich glaube das Komma muss an dieser Stelle maskiert werden, auch wenn es dort kein Sonderzeichen ist.

      Glaube versetzt Berge, aber in einer Zeichenklasse gibt es imn Gegensatz zu außerhalb nur nur ganz wenige Zeichen mit besonderer Bedeutung. Das wären \ - ^ (am Anfang). Unabhängig davon kann man aber seinem Glauben Nachdruck mithilfe ein paar überflüssiger Maskierungen verleihen. Macht die ganze Sache nur nicht übersichtlicher. Zumal man ja auch noch die Maskierungen für PHP-Strings mit berücksichtigen muss. Es ist jetzt schon ein Mix drin. Die ( und ) maskieren die Klammer für den Ausdruck, das ' hingegen maskiert das ' für den PHP-String.

      Außerdem möchtest du in der Zeichenklasse sicher auch Großbuchstaben und Umlaute zulassen.

      Die nicht erlaubten Großbuchstaben sind der Grund für das Nicht-Matchen. Aber warum nur auf Umlaute beschränken? Was ist an anderen Zeichen anders, dass sie entgegen der Umlaute nicht genommen werden dürfen? Andererseits würde ich das Problem dadurch lösen, dass ich englische Bezeichner nähme. Oder zumindest bei den deutschen Bezeichnern die Ersatzschreibweise. MySQL kommt zwar mit Nicht-ASCII in den Bezeichnern klar, aber man muss sich ja nicht unnötig Probleme ins Haus holen.

      Ich glaube aber nicht, dass du mit einem Parser auf Basis von regulären Ausdrücken hundertprozentige Korrektheit erreichen wirst,  [...]

      Der Theoretiker stimmt dir dabei zu, der Praktiker sagt sich aber: Wozu dieser Aufwand (des Erstellens und des Prüfens auf Fehlerfreiheit aller möglichen und unmöglichen Konstellationen), wenn der auf absehbare Zeit nicht zum Tragen kommen wird? "Komische" Zeichen in Bezeichnern machen nicht nur da Probleme, so dass man üblicherweise gleich von vornherin darauf verzichtet. Anders sieht es aus, wenn man ein Projekt erarbeitet, dass der Allgemeinheit zugute kommen soll. Da wäre der Aufwand gerechtfertigt, wenn man die Anwender nicht in ihrer Kreativität einschränken möchte. Bei den gezeigten Bezeichnern sieht es jedoch sehr nach Individualprojekt aus, da kann man sich guten Gewissens auf ein Mindestmaß einschränken.

      dedlfix.

      1. Hakuna matata!

        Glaube versetzt Berge

        Das kann ich nicht bezeugen, aber ich habe gesehen, dass Glaube Wolkenkratzer zusammenstürzen lassen kann.

        Die nicht erlaubten Großbuchstaben sind der Grund für das Nicht-Matchen. Aber warum nur auf Umlaute beschränken?

        Ja, da hab ich Quatsch erzählt. Eigentlich könnte man alles bis auf die schließende Klammer erlauben: [^)] Und wenn man die schließende Klammer doch erlauben möchte, dann müsste man wie gehabt zu einem anderen Ansatz als regulären Ausdrücken greifen.

        Ich glaube aber nicht, dass du mit einem Parser auf Basis von regulären Ausdrücken hundertprozentige Korrektheit erreichen wirst,  [...]

        Der Theoretiker stimmt dir dabei zu, der Praktiker sagt sich aber: Wozu dieser Aufwand

        ACK.

        --
        “All right, then, I'll go to hell.” – Huck Finn
        1. Liebe Mitdenker,
          liebe Wissende,
          liebe Neugierige,

          ja!

          Glaube versetzt Berge

          Das kann ich nicht bezeugen, aber ich habe gesehen, dass Glaube Wolkenkratzer zusammenstürzen lassen kann.

          Oder waren das doch die bereits beim Bau für den späteren Abriss eingebrachten Sprengladungen?
          Sooo sauber und punktgenau kann nämlich auch Glaube nicht abreißen.
          Fragt sich nur, wieviele Wolkenkratzer noch genauso präpariert sind.

          Spirituelle Grüße
          Euer Robert

          --
          Möge der Forumsgeist wiederbelebt werden!
          1. Fragt sich nur, wieviele Wolkenkratzer noch genauso präpariert sind.

            Ich halte die Darstellung, wonach die Aufhängungen der Böden/Decken weich geworden sind und dass dann die abstürzenden Platten die darunter befindlichen regelrecht herausgebombt haben, für glaubwürdig.

            Stahl, der 20 °C Celsius hat, verhält sich ganz anders als Stahl, der in einigen Stunden Brand trotz Isolierung auf weit über 400 °C erhitzt wurde. Damit, dass jemand Hektoliterweise Kerosin in ein Hochhaus pumpt, hat der Architekt (dem da was einfallen ist) nicht gerechnet.

            Was glaubst Du, wie viel kinetische Energie so 5 bis 10 Tonnen frei fallender Beton auf 3m Deckenhöhe aufnimmt und auf die darunter liegende Decke - mit ebenfalls weichen Aufhängungen abgibt? Es macht überhaupt nichts aus, wenn dann 3 Stockwerke tiefer die Aufhängungen intakt sind - die halten das einfach nicht aus.

            Du kannst davon ausgehen, dass praktisch alle Wolkenkratzer auf diese Weise errichtet wurden und werden: Hochstrebendes Skelett, eingehängte Böden, die Fahrstuhlschächte und Treppenhäuser als Stabilisierung, manchmal noch innen verspannt. Aber die Decken sind eingehängt und sorgen auch dafür, dass das Ding nicht auseinander klappt. Fehlen die Decken (weil runter gefallen) dann passiert genau das was dort zu sehen war. Deshalb ist auch das hochstrebende Skelett auseinander und dann runtergefallen und die die das Gebäude stabilisierenden Fahrstuhl- und Treppenhausschächte haben auch einfach zu viel seitlichen Zug bekommen, sind gebrochen wie Makkaroni und auch diese tonnenschweren Bruchstücke haben sich nicht etwa wie Luftschiffe verhalten sondern nach dem kürzest möglichen Weg nach unten gesucht.

            Das meiste von dem, was in solchen Gebäuden wie eine Wand aussieht, ist, naja, Pappe und Gipskarton...

            Falls Du jetzt meinst, die Türme hätten zur Seite fallen müssen, dann überlege mal warum die das hätten tun sollen. Die Schwerkraft zieht nach unten und bei der relativ großen Fläche und der Art des Zusammenbruchs von fast ganz oben nach unten sieht das für gänzlich unbedarfte Laien halt so aus wie eine recht gut gelungene Sprengung.

            Ich war schon mal dabei als ein komplett mit Wasser gefüllter Behälter mit einer Wandstärke von irgendwas zwischen 10 und 20cm, durch "simples" Aufpumpen mit Luft auf über 400 "Atü" gesprengt wurde. Ich wusste es vorher - seit dem aber ganz genau, dass auch das was so irre fest aussieht, nur begrenzt fest ist.

            Jörg Reinholz

            1. Abgesehen davon glaube ich aber auch, dass man bei CIA und NSA nach den Ereignissen nicht etwas aus Angst sondern zum Lachen tagelang im Keller musste. Die haben natürlich genau gewusst, dass denen sowas "jeden Grund zu allem" liefert. Und dass die USA - und nicht nur die USA - sich inzwischen zu quasifaschistischen Regimes entwickelt haben steht für mich auch fest.

              Jörg Reinholz

    2. Hakuna matata!

      [Field] => class
                  [Type] => set('Hotel','Pension','Lodge','Ferienhaus','Ferienwohnung')
                  [Null] => YES
                  [Key] =>
                  [Default] =>
                  [Extra] =>

      Das sieht für mich nach einer Datenbank-Abstraktionsschicht aus, stimmt das? Wenn ja, dann gibt es vielleicht in der Bibliothek schon einen Parser für das Type-Feld, welche Bibliothek benutzt du denn?

      $pm = preg_match('~([a-z]+)((['a-z,0-9]*))~', $columns['Type'], $matches);

      Ich glaube das Komma muss an dieser Stelle maskiert werden, auch wenn es dort kein Sonderzeichen ist. Außerdem möchtest du in der Zeichenklasse sicher auch Großbuchstaben und Umlaute zulassen.

      So dämlich kann man auch nur vorbeigucken :-O
      Danke, das war es natürlich!

      Es kommen in den Werten einer set()-Liste auch Großbuchstaben und eventuell sogar Sonderzeichen und Umlaute vor. Deshalb hat es selbstverständlich _nicht_ funktioniert. Jetzt muss ich erst einmal über Codierung nachdenken, befürchte ich. Da war doch 'was mit preg_match? Außerdem soll die Klasse für utf-8 und für iso8859-1 benutzbar sein. Muss ich also noch überlegen, wie man sowas macht.

      Das obige Array wird bei MySQL als Select-Ergebnis auf "Show columns from tablename" pro Spalte der Tabelle geliefert. Ich will es für meine Standard Input-Output-Klasse auswerten.

      RR

      1. Tach!

        Es kommen in den Werten einer set()-Liste auch Großbuchstaben und eventuell sogar Sonderzeichen und Umlaute vor. [...] Jetzt muss ich erst einmal über Codierung nachdenken, befürchte ich. Da war doch 'was mit preg_match? Außerdem soll die Klasse für utf-8 und für iso8859-1 benutzbar sein.

        Es gibt den Modifizierer u (klein, das große steht für ungreedy). Wenn der vorhanden ist, dann wird Muster _und_ Text gemäß UTF-8 interpretiert. Den musst du dann eben in Abhängigkeit setzen oder nicht. Das Problem dabei ist, dass du dann auch die Nicht-ASCII-Zeichen mal so und mal so kodiert in das Suchmuster schreiben musst.

        Das obige Array wird bei MySQL als Select-Ergebnis auf "Show columns from tablename" pro Spalte der Tabelle geliefert. Ich will es für meine Standard Input-Output-Klasse auswerten.

        Wenn das was generelles werden soll, musst du dir wohl doch noch ein paar mehr Gedanken zu den erlaubten/vorkommenden Zeichen und deren maskierter Darstellung machen.

        dedlfix.

        1. Liebe Mitdenker,
          liebe Wissende,
          liebe Neugierige,

          ja!

          Es kommen in den Werten einer set()-Liste auch Großbuchstaben und eventuell sogar Sonderzeichen und Umlaute vor. [...] Jetzt muss ich erst einmal über Codierung nachdenken, befürchte ich. Da war doch 'was mit preg_match? Außerdem soll die Klasse für utf-8 und für iso8859-1 benutzbar sein.

          Es gibt den Modifizierer u (klein, das große steht für ungreedy). Wenn der vorhanden ist, dann wird Muster _und_ Text gemäß UTF-8 interpretiert. Den musst du dann eben in Abhängigkeit setzen oder nicht. Das Problem dabei ist, dass du dann auch die Nicht-ASCII-Zeichen mal so und mal so kodiert in das Suchmuster schreiben musst.

          Das obige Array wird bei MySQL als Select-Ergebnis auf "Show columns from tablename" pro Spalte der Tabelle geliefert. Ich will es für meine Standard Input-Output-Klasse auswerten.

          Wenn das was generelles werden soll, musst du dir wohl doch noch ein paar mehr Gedanken zu den erlaubten/vorkommenden Zeichen und deren maskierter Darstellung machen.

          Bin ich dabei.
          Alternativ habe ich auch

            
          select COLUMN_NAME, COLUMN_DEFAULT, IS_NULLABLE,  
              DATA_TYPE, CHARACTER_MAXIMUM_LENGTH,  
              NUMERIC_PRECISION, NUMERIC_SCALE, CHARACTER_SET_NAME,  
              COLLATION_NAME, COLUMN_TYPE, COLUMN_COMMENT  
          from information_schema.columns where table_name='test';  
            
          
          

          im Visier. Leider muss ich trotzdem COLUMN_TYPE auseinandernehmen, um an die Werte für Set und Enum heranzukommen. Da habe ich also nicht viel gewonnen, mit Ausnahme von COLUMN_COMMENT.

          Spirituelle Grüße
          Euer Robert

          --
          Möge der Forumsgeist wiederbelebt werden!
  2. Hallo Robert,

    Ich will im ersten Schritt nur den Typbezeichner und die Spezifikation auseinander klamüsern.

    Andere haben ja auf den Fehler schon hingewiesen (Beschränkung auf a-z). Statt A-Za-z0-9_ könntest du auch das shorthand \w integrieren:  [\w\',]

    Wenn $columns['Type'] immer so aufgebaut ist und Klammern jeweils nur an Anfang/Ende vorkommen, könnte man ev auch die schließende Klammer entfernen und explode() verwenden:

    $parts = explode("(", rtrim($columns['Type'], ")"));  
    
    

    Ansonsten z.b. preg_split();

    $parts = preg_split('~^\w+\K\(~', rtrim($columns['Type'], ")"));  
    
    

    Gesplittet wird hier bei der ersten öffnenden Klammer nach string start und ein oder mehreren \w.

    Schöne Grüße, Robert

  3. Angenommen, der Backslash ist das Escape-Zeichen für single quotes in single quotes:

    <?php  
      
    $pattern = '  
        /  
        \'  
        (?:  
            \\\\{2} # treffe zwei Backslashes  
            |  
            \\\\.   # oder einen Backslash und ein beliebiges Zeichen  
            |  
            [^\\\\] # oder ein Zeichen, das kein Backslash ist  
        )*?  
        \'  
        /sx';  
      
    $subject = "set('Hotel','Pension','Lodge','Ferienhaus','Ferienwohnung')";  
      
    $matches = array();  
    preg_match_all($pattern, $subject, $matches);  
    $tmp = $matches[0];  
    array_walk($tmp, function (&$s) {  
        $s = trim($s, '\'');  
    });  
    var_dump($tmp);  
      
    //array(5) {  
    //  [0]=>  
    //  string(5) "Hotel"  
    //  [1]=>  
    //  string(7) "Pension"  
    //  [2]=>  
    //  string(5) "Lodge"  
    //  [3]=>  
    //  string(10) "Ferienhaus"  
    //  [4]=>  
    //  string(13) "Ferienwohnung"  
    //}
    

    Fallunterscheidung, ob es ein set() ist oder sonst was, dürfte ja hinzubekommen sein.

    1. Sorry, hier steckt ein Bug:

      array_walk($tmp, function (&$s) {

      $s = trim($s, ''');
      });

        
      Muss wohl doch so:  
        
      ~~~php
      array_walk($tmp, function (&$s) {  
          $s = substr($s, 1, -1);  
      });
      

      Der Grund ist, dass Einträge in $s mit einem escapten single quote enden könnten. Das würde trim() dann auch mit abschneiden.

      Ist zwar sowieso keine vollständige Lösung, aber so ist es immerhin richtiger.