[Regexp] define Befehle aus Quelltext Dateien parsen

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • [Regexp] define Befehle aus Quelltext Dateien parsen

    Für ein Übersetzungsprojekt stehe ich vor folgendem Problem:

    Ich möchte per PHP die xtc:modify Shop Sprachdateien parsen und habe mir dafür schon ein Regexp ersonnen:
    Code:
    define\(["']([^"']+)["'][ ]*,[ ]*(.*)\);([ ]*[\/]*.*)
    Der Ausdruck würde eine Zeile in die Bezeichnung eines PHP define Befehl, dessen Inhalt und evtl. vorhandene Bemerkung zerlegen. Klappt in Tests auch schon prima.

    PHP-Code:
    define('TITLE'STORE_NAME);
    define('DATE_FORMAT_SHORT','(*); %d.%m.%Y');  // this is used for strftime() 
    wird zu

    PHP-Code:
    TITLE => STORE_NAME
    DATE_FORMAT_SHORT 
    => '(*);*%d.%m.%Y'   Bemerkung// this is used for strftime() 
    Jetzt meine Frage: Wie kann ich den Ausdruck sicher für mehrzeilige define Befehle gestalten? Da hapert es etwas bei mir.

    PHP-Code:
    define('DATE_FORMAT_SHORT',
        
    '%d.%m.%Y');// Mehrzeilig geht leider nicht :( 
    Als PHP Befehl möchte ich preg_match_all verwenden. Welche Modifikatoren und Ausdruck-Änderungen muss ich für die mehrzeilige Suche verwenden?

    Vielen Dank schonmal für Eure Tipps.
    Zuletzt geändert von RossiRat; 18.03.2011, 16:16. Grund: Gelöst eingefügt

  • #2
    ich hab zwar mit regulären ausdrücken noch nicht so gearbeitet aber so wie ich das verstehe benötigst du den modifier "m"

    Kommentar


    • #3
      Was sollen die [*]* bewirken? Der Befehl define('CONST'*, 'Text'); führt zu einem Parse error. Was willst du da abfangen?

      Versuchs mal damit, \s* vor und nach das Komma und die Klammern zu setzen, dann bist du auf der sicheren Seite.
      This is what happens when an unstoppable force meets an immovable object.

      Kommentar


      • #4
        Zitat von ApoY2k Beitrag anzeigen
        Was sollen die [*]* bewirken? Der Befehl define('CONST'*, 'Text'); führt zu einem Parse error. Was willst du da abfangen?

        Versuchs mal damit, \s* vor und nach das Komma und die Klammern zu setzen, dann bist du auf der sicheren Seite.
        Entschuldige bitte, irgendwie sind beim Reinkopieren aus Leerzeichen Sternchen geworden?!?

        Ich habe den Ausdruck berichtigt. Hier noch mal zur besseren Ansicht:
        Code:
        define\(["']([^"']+)["'][ ]*,[ ]*(.*)\);([ ]*[\/]*.*)
        Die [ ]* benutze ich um beliebig viele Leerzeichen zu finden. Man kann zwar das Leerzeichen auch setzen ohne eine Klasse mit den Klammern zu machen. Aber ich habe mir das mal so angewöhnt, da man so nicht so schnell ein Leerzeichen übersehen kann.

        Wenn ich den /m Modifikator (Multiline) setze, dann werden alle Zeilen bis zum Ende der Datei als eine Zeile gefunden. Da müsste irgendwie noch eine Abfrage rein das er Multiline nutzt aber bei define einen neuen Datensatz anfängt. Und das kriege ich nicht hin.

        Edit:
        Ausdruck endlich richtig reinkopiert!
        Zuletzt geändert von RossiRat; 01.10.2010, 14:11.

        Kommentar


        • #5
          Hallo,

          du kannst auch PHPs eingebauten Tokenizer nutzen. Das ist zuverlässiger als selbgestrickte RegExe.

          Gruß,

          Amica
          [COLOR="DarkSlateGray"]Hast du die [COLOR="DarkSlateGray"]Grundlagen zur Fehlersuche[/color] gelesen? Hast du Code-Tags benutzt?
          Hast du als URL oder Domain-Beispiele example.com, example.net oder example.org benutzt?
          Super, danke!
          [/COLOR]

          Kommentar


          • #6
            Eine neue Zeile ist kein Leerzeichen. Wenn du neue Zeilen einbinden willst, musst du dem Ausdruck das auch mitteilen.

            PHP-Code:
            preg_match_all('#define\s*\(\s*["\']([^"\']+)["\']\s*,\s*(.*)\s*\); *(//.*)*#'$define$matches); 
            Zuletzt geändert von ApoY2k; 01.10.2010, 14:43.
            This is what happens when an unstoppable force meets an immovable object.

            Kommentar


            • #7
              Zitat von ApoY2k
              Eine neue Zeile ist kein Leerzeichen. Wenn du neue Zeilen einbinden willst, musst du dem Ausdruck das auch mitteilen.
              Genau das war mein Problem. Ich hatte es auch schon mit \n probiert. Hatte wohl einen leichten Knoten im Gehirn.

              Zitat von ApoY2k
              PHP-Code:
              preg_match_all('#define\s*\(\s*["\']([^"\']+)["\']\s*,\s*(.*)\s*\); *(//.*)*#'$define$matches); 
              Funktioniert prima! Vielen Dank Apo!


              @Amica
              Der Tokenizer hört sich sehr interessant an. Damit habe ich noch nicht gearbeitet. Aber wenn der PHP Befehl define nicht in der Tokenliste drin steht, kann ich dann trotzdem den Tokenizer nutzen?
              Zuletzt geändert von RossiRat; 01.10.2010, 15:38.

              Kommentar


              • #8
                Zitat von RossiRat Beitrag anzeigen
                Der Tokenizer hört sich sehr interessant an. Damit habe ich noch nicht gearbeitet. Aber wenn der PHP Befehl define nicht in der Tokenliste drin steht, kann ich dann trotzdem den Tokenizer nutzen?
                define ist eine Funktion, wird also auch als solche vom Tokenizer erkannt.
                I don't believe in rebirth. Actually, I never did in my whole lives.

                Kommentar


                • #9
                  Habe den Tokenizer mal getestet und mir ist dabei aufgefallen, dass, wenn der define über mehrere Zeilen geht, die neuen Zeilen als Token registriert werden. Mit anderen Worten, wenn man

                  PHP-Code:
                  define('const','text'); 
                  In Tokens umwandelt, erhält man

                  PHP-Code:
                  => define
                  => (
                  => 'const'
                  => ,
                  => 'text'
                  => )
                  => ; 
                  (Vereinfacht dargestellt)

                  Wenn man hingegen
                  PHP-Code:
                  define('const',
                  'text'); 
                  umwandelt, wird daraus

                  PHP-Code:
                  => define
                  => (
                  => 'const'
                  => ,
                  =>

                  => 'text'
                  => )
                  => ; 
                  Das gleiche passiert auch bei Leerzeichen

                  PHP-Code:
                  define('const''text'); 
                  wird zu

                  PHP-Code:
                  => define
                  => (
                  => 'const'
                  => ,
                  =>
                  => 'text'
                  => )
                  => ; 
                  This is what happens when an unstoppable force meets an immovable object.

                  Kommentar


                  • #10
                    Zitat von ApoY2k Beitrag anzeigen
                    Habe den Tokenizer mal getestet und mir ist dabei aufgefallen, dass, wenn der define über mehrere Zeilen geht, die neuen Zeilen als Token registriert werden.
                    Ja - und was willst du uns jetzt damit sagen ...?

                    Zeilenumbrüche und Leerzeichen stellen nun mal Token vom Typ T_WHITESPACE dar.
                    I don't believe in rebirth. Actually, I never did in my whole lives.

                    Kommentar


                    • #11
                      Naja, wie soll man rausfinden auf welche Felder man zugreifen soll, um an die Daten, die man möchte zu kommen? Mal ist es 5, mal 6.
                      This is what happens when an unstoppable force meets an immovable object.

                      Kommentar


                      • #12
                        Zitat von ApoY2k Beitrag anzeigen
                        Naja, wie soll man rausfinden auf welche Felder man zugreifen soll, um an die Daten, die man möchte zu kommen? Mal ist es 5, mal 6.
                        Mal enthält der Code an der Stelle ja auch Whitespace, und mal nicht ...

                        Und für die Tokens wird jeweils ein Array geliefert, in dem auch der Typ explizit aufgeführt ist. Was kein Arrays ist, ist auch kein Token, sondern sonstiges (Syntax-)Zeichen.
                        I don't believe in rebirth. Actually, I never did in my whole lives.

                        Kommentar


                        • #13
                          Das Problem mit dem Tokenizer ist, dass er auch nur Mustererkennung macht, aber er "parst" nicht. Wenn jetzt die Ausdrücke, die define() übergeben werden, komplexer sind, als bspw. zwei skalare Werte, muss man sich selbst einen Parser stricken. Man denke nur an durch Klammern verschachtelte Ausdrücke ...

                          Also ist der Tokenizer auch nicht viel mehr wert als ein bisschen preg_match() mit einem etwas größeren RegEx.

                          Zitat von RossiRat
                          ...
                          Der Ausdruck würde eine Zeile in die Bezeichnung eines PHP define Befehl, dessen Inhalt und evtl. vorhandene Bemerkung zerlegen. Klappt in Tests auch schon prima.
                          ...
                          Jetzt meine Frage: Wie kann ich den Ausdruck sicher für mehrzeilige define Befehle gestalten?
                          Ersetze alle Stellen, an denen im Quelltext ein Leer- oder Zeilentrennzeichen auftreten könnte (das sind so einige) durch so etwas wie '\s*' oder '\s+' (je nachdem, was der PHP-Parser für zulässig erachtet). Und weil du den Punkt|Dot '.' als Musterzeichen verwendest, gehört ein '/s' (== "dot all") hinter den RegEx, denn String-Literale können in PHP-Quelltexten auch über mehrere Zeilen gehen.

                          Was willst du eigentlich "parsen"? Willst du nur ein paar Daten extrahieren oder den Quellcode modifizieren?

                          PHP-Code:
                          preg_match_all(
                              
                          '/\s*define\s*\(\s*'.
                              
                          '\'([^\']+)\'\s*,\s*'.
                              
                          '\'([^\']+)\''.
                              
                          '\s*\)\s*;\s*'.
                              
                          '//([^\r\n]+)/sx'
                              
                          $src
                              
                          $hits
                          ); 
                          Das sollte dir den Kommentar und die beiden Zeichenketten zeigen, die define() übergeben wurden.

                          Um das Ganze aber solider zu machen, muss man noch die Erkennung der "Hochkommas" verfeinern (es fehlen die doppelten) und berücksichtigen, dass das gesamte Muster auch in (ein und mehrzeiligen) Kommentaren und String-Literalen vorkommen darf, dort sollte es aber ignoriert werden.
                          Zuletzt geändert von fireweasel; 01.10.2010, 21:19.
                          Klingon function calls do not have “parameters”‒they have “arguments”‒and they always win them!

                          Kommentar


                          • #14
                            Vielen vielen Dank für Eure Hilfe! Bisher habe ich eher mit einfachen RegEx gearbeitet.

                            Ich bin gerade dabei mir einen neuen modify Shop einzurichten. Dabei habe ich feststellen müssen das einige Übersetzungen leider noch nicht vollständig vorhanden sind. Dazu möchte ich ein Unterstützungs-Tool programmieren.

                            Ich parse die Originale xtc_modify Sprachdatei in Deutsch und lege eine Tabelle mit den Schlüsseln und Werten an. Danach werden die anderen installierten Sprachen geparst und an die vorhandenen Schlüssel angehängt. Am Ende bekommt man etwas präsentiert was wie eine Excel Tabelle aussieht, in der man sofort erkennt welche Schlüssel noch nicht übersetzt sind.

                            Kommentar


                            • #15
                              Zitat von RossiRat Beitrag anzeigen
                              Vielen vielen Dank für Eure Hilfe! Bisher habe ich eher mit einfachen RegEx gearbeitet.
                              Oh, mein Vorschlag war ein einfacher RegEx: ein wenig Pattern-Matching, nicht mehr. Er sieht nur so komisch aus, weil an jeder möglichen Stelle ein '\s*' eingefügt wurde, um auch alle (Stellen) zu erfassen, wo der PHP-Parser beim Übersetzen eines Scriptes Leerzeichen erlaubt. '\s' steht für "white space" und erfasst auch Tabulator-Zeichen, Zeilenumbrüche usw.


                              Ich bin gerade dabei mir einen neuen modify Shop einzurichten. Dabei habe ich feststellen müssen das einige Übersetzungen leider noch nicht vollständig vorhanden sind. Dazu möchte ich ein Unterstützungs-Tool programmieren.
                              Ohne Not sollte man sich keine Arbeit machen, die schon andere getan haben ...

                              Ein größeres Open-Source-Projekt, das was taugt, benutzt für die Lokalisierung üblicherweise ein weitverbreitetes Standardwerkzeug oder bietet wenigstens ein eigenes an. Hat xtc:modify keines? Das wäre (für mich) ein schlechtes Zeichen. Oder benutzt es das gleiche Lokalisierungsformat wie sein Ursprungsprojekt xt-commerce?
                              Zuletzt geändert von fireweasel; 03.10.2010, 22:37.
                              Klingon function calls do not have “parameters”‒they have “arguments”‒and they always win them!

                              Kommentar

                              Lädt...
                              X