Gabriel: Reguläre Ausdrücke

Hallo,

ich habe in einem Projekt einen simplen Template-Parser, der unter anderem die gesamte Ausgabe nach E-Mail-Adressen durchsucht und sie zum Schutz gegen Bots per JS "verschlüsselt" bzw. durch Bilder ersetzt. Dafür verwende ich folgenden Code und der funktioniert soweit auch einwandfrei - für das Ersetzen ist die Methode encode_email_adress zuständig:
preg_replace_callback("/([a-zA-Z0-9_\-\.]+@[a-zA-Z0-9_\-\.]+\.[a-zA-Z]{2,6})/i", create_function('$treffer', 'return contentmanagement::encode_email_adress($treffer[0]);'), $text )

Allerdings kann es zu Problemen kommen, sobald eine E-Mail-Adresse von einem Benutzer in ein Formular eingegeben wurde. Wenn das Formular nicht korrekt ausgefüllt wurde werden nach dem Prinzip der Sticky Forms alle korrekten Eingaben wieder in die entsprechenden Felder eingefügt - und in JS-Code bzw. Links auf Bilder ersetzt, was nicht sein soll. Folgender Codeversuche funktionieren leider nicht:
preg_replace_callback("/^(value=\")([a-zA-Z0-9_\-\.]+@[a-zA-Z0-9_\-\.]+\.[a-zA-Z]{2,6})/i", create_function('$treffer', 'return contentmanagement::encode_email_adress($treffer[1]);'), $text )
preg_replace_callback("/(value=\"){0}([a-zA-Z0-9_\-\.]+@[a-zA-Z0-9_\-\.]+\.[a-zA-Z]{2,6})/i", create_function('$treffer', 'return contentmanagement::encode_email_adress($treffer[1]);'), $text )

Kurz: ich suche einen regulären Ausdruck, der 'test@test.de' immer erkennt, außer im Fall 'value="test@test.de"'.

Noch besser wäre auch, wenn er auch '<textarea>[...]test@test.de[...]</textarea>' nicht erkennt, aber das dürfte eigentlich nicht vorkommen und eine solche Erkennung ist vermutlich nicht sehr performant.

Ich würde mich sehr freuen, wenn mir jemand weiterhelfen könnte. Im Prinzip müsste es doch nur daran hängen den Block "(value=")" sauber zu negieren - nur wie?

Grüße
Gabriel

  1. 你好 Gabriel,

    Im Prinzip müsste es doch nur daran hängen den Block "(value=")" sauber zu negieren - nur wie?

    Das wirst du nicht hinbekommen, denke ich. Prinzipiell gibt es für sowas zwar negative lookbehind assertion:

    (?<!value=")\w+@\w+.\w+

    Aber das nutzt dir nichts. Denn der RegEx matcht zwar nicht auf „value="abc@abc.de”, wohl aber auf „bc@abc.de” (dem vorher ein „value="a” folgt) – und das würde dir nicht viel helfen, vor allem, weil lookbehind assertion eine feste Länge haben muss, du also auch nicht mit * oder + arbeiten kannst.

    再见,
     克里斯蒂安

    --
    http://wwwtech.de/
    <g[oma]> peter lustig ist auf jeden fall besser als peter huth, obwohl der auch lustig ist.
    Kompromisse und andere WiderlichkeitenHochzeit mit Flitterwochen
    1. Hallo Christian

      Im Prinzip müsste es doch nur daran hängen den Block "(value=")" sauber zu negieren - nur wie?

      Das wirst du nicht hinbekommen, denke ich. Prinzipiell gibt es für sowas zwar negative lookbehind assertion:

      (?<!value=")\w+@\w+.\w+

      Aber das nutzt dir nichts. Denn der RegEx matcht zwar nicht auf „value="abc@abc.de”, wohl aber auf „bc@abc.de” (dem vorher ein „value="a” folgt) – und das würde dir nicht viel helfen, vor allem, weil lookbehind assertion eine feste Länge haben muss, du also auch nicht mit * oder + arbeiten kannst.

      Etwas in der Richtung hatte ich befürchtet. Ich hatte mir das Thema Lookbehind-Assortion zwar schon angeschaut, aber dafür reichen meine RegEx-Kenntnisse leider nicht weit genug.

      Es wäre aber trotzdem sehr schade, wenn es wirklich nicht funktionieren sollte. Dir auf jeden Fall schon mal vielen Dank für die Antwort.

      Gruß
      Gabriel

      1. 你好 Gabriel,

        Es wäre aber trotzdem sehr schade, wenn es wirklich nicht funktionieren sollte. Dir auf jeden Fall schon mal vielen Dank für die Antwort.

        Natürlich ist das Problem lösbar. Nur halt nicht mit regulären Ausdrücken. Du musst halt den String Zeichenweise durchlaufen, erkannte Mail-Adressen umwandeln und dabei notieren, ob du dich in einem value=" befindest. Ist das der Fall, wird die Umwandlung ausgesetzt, bis du auf ein " triffst.

        再见,
         克里斯蒂安

        --
        http://wwwtech.de/
        Sobald dir ein Gedanke kommt, lache über ihn.
        Kompromisse und andere WiderlichkeitenHochzeit mit Flitterwochen
  2. Hallo Gabriel,

    /([a-zA-Z0-9_-.]+@[a-zA-Z0-9_-.]+.[a-zA-Z]{2,6})/i

    darf ich mal fragen, warum Du Klasse [a-zA-Z] nutzt, wenn Du eh den Modifikator i verwendest? Darüber hinaus ist unter sehr vielen anderen Möglichkeiten die mail-Adresse .e@_..de ungültig, wird aber von Deinem pattern erfasst. Dagegen ist die mail-Adresse eddi{privat}@example.com gültig, wird aber von Deinem pattern nicht erfasst.

    Ein halbwegs gescheiter Ausdruck nur zum erfassen des lokalen Teils mit @-Zeichen einer mail-Adresse sähe etwa so aus:

    '#("[a-z0-9!\#$%&\'*+\-\/:;<=>?@\[\]^_{|}~. ]{0,62}"|[a-z0-9!#$%&'+-/=?^_{|}~][a-z0-9!\#$%&\'*+\-\/=?^_{|}~.]{0,62}[a-z0-9!#$%&'+-/=?^_{|}~])@#i'

    Eine Domain korrekt zu erkennen, soviel darf ich schon mal verraten, ist noch mal komplexer…

    … Wenn das Formular nicht korrekt ausgefüllt wurde werden nach dem Prinzip der Sticky Forms alle korrekten Eingaben wieder in die entsprechenden Felder eingefügt - und in JS-Code bzw. Links auf Bilder ersetzt, was nicht sein soll.

    Das lässt sich doch sinnvoll mit einer einfachen Kontrollstruktur eindämmen:

    if(!pruefe_formulareingaben()){  
       sende_formular_zurueck();  
       exit;  
    }  
    konvertiere_mail_adressen();
    

    Hier RegExp zu verwenden, bedeutet doch unnötig Arbeit.

    Gruß aus Berlin!
    eddi

    1. Hallo eddi

      /([a-zA-Z0-9_-.]+@[a-zA-Z0-9_-.]+.[a-zA-Z]{2,6})/i

      darf ich mal fragen, warum Du Klasse [a-zA-Z] nutzt, wenn Du eh den Modifikator i verwendest?

      Das ist eine gute Frage - das i(nsensitive) fehl am Platze, da hast du vollkommen recht.

      Darüber hinaus ist unter sehr vielen anderen Möglichkeiten die mail-Adresse .e@_..de ungültig, wird aber von Deinem pattern erfasst. Dagegen ist die mail-Adresse eddi{privat}@example.com gültig, wird aber von Deinem pattern nicht erfasst.
      [...]
      Eine Domain korrekt zu erkennen, soviel darf ich schon mal verraten, ist noch mal komplexer…

      Das ist mir klar und ich habe auch nicht die Absicht Adressen zu 100% zu validieren. Ich will mit dem RegEx nur Adressen, die im Backend eingegeben werden durch etwas "Bot-sicherere" Varianten ersetzen. Hier macht es nichts, wenn eine ungültige Adresse als gültige erkannt wurde, wenn mit dem "Text" eine E-Mail-Adresse gemeint war.

      … Wenn das Formular nicht korrekt ausgefüllt wurde werden nach dem Prinzip der Sticky Forms alle korrekten Eingaben wieder in die entsprechenden Felder eingefügt - und in JS-Code bzw. Links auf Bilder ersetzt, was nicht sein soll.

      Das lässt sich doch sinnvoll mit einer einfachen Kontrollstruktur eindämmen:

      if(!pruefe_formulareingaben()){

      sende_formular_zurueck();
         exit;
      }
      konvertiere_mail_adressen();

      
      >   
      > Hier RegExp zu verwenden, bedeutet doch unnötig Arbeit.  
        
      Ja und nein. In dem System besteht jede Seite aus mehreren Bereichen / Records. Dieser RegEx läuft über die Seite kurz vor deren Auslieferung und weiß nicht, ob das, was das untersucht werden soll ein (statischer) Record mit einer zu ersetzenden E-Mail-Adresse ist oder einer, der ein Formular enthält.  
      Die "unnötige Arbeit", die ich mir und der Performance des Systems sparen will, ist die Prüfung über alle einzelnen Bestandteile laufen zu lassen und dann für jeden Bestandteil der Seite extra zu prüfen, ob dieser Bestandteil überprüft werden soll oder nicht.  
        
      Gruß  
      Gabriel
      
      1. Re:

        Ich will mit dem RegEx nur Adressen, die im Backend eingegeben werden durch etwas "Bot-sicherere" Varianten ersetzen.

        Ja, okay; nur warum schützt Du jemanden nicht, der eine gültige mail-Adresse hat, die nicht Deinem simplen pattern entspricht?

        … Wenn das Formular nicht korrekt ausgefüllt wurde werden nach dem Prinzip der Sticky Forms alle korrekten Eingaben wieder in die entsprechenden Felder eingefügt - und in JS-Code bzw. Links auf Bilder ersetzt, was nicht sein soll.

        Das lässt sich doch sinnvoll mit einer einfachen Kontrollstruktur eindämmen:

        if(!pruefe_formulareingaben()){

        sende_formular_zurueck();
           exit;
        }
        konvertiere_mail_adressen();

        
        > >   
        > > Hier RegExp zu verwenden, bedeutet doch unnötig Arbeit.  
        >   
        > Ja und nein. In dem System besteht jede Seite aus mehreren Bereichen / Records. Dieser RegEx läuft über die Seite kurz vor deren Auslieferung und weiß nicht, ob das, was das untersucht werden soll ein (statischer) Record mit einer zu ersetzenden E-Mail-Adresse ist oder einer, der ein Formular enthält.  
          
        So wie sich das für mich liest, hast Du also einen output-handler gebastest, der mit allerlei RegEx über den Pufferinhalt läuft. Das schließt aber nicht aus, diesen bedingt abzuschalten. Jedenfalls ist das Konzept verkehrt. Man braucht auch keine Streu- und Räumfahrzeuge bei der Verkehrswacht im Sommer.  
          
        
        > Die "unnötige Arbeit", die ich mir und der Performance des Systems sparen will, ist die Prüfung über alle einzelnen Bestandteile laufen zu lassen und dann für jeden Bestandteil der Seite extra zu prüfen, ob dieser Bestandteil überprüft werden soll oder nicht.  
          
        Es hat auch mit Performanz zu tun, Dokumente nicht nach mail-Adressen abzuklappern, die definitiv keinem bot serviert werden. Das ist der eigentliche Punkt.  
        Baue also eine Logik ein, die die mail-Adressprüfung abschalten kann!  
          
          
        Gruß aus Berlin!  
        eddi
        
  3. Kurz: ich suche einen regulären Ausdruck, der 'test@test.de' immer erkennt, außer im Fall 'value="test@test.de"'.

    Die Stiftung Warentest wird sich freuen.