Stefan Kleeschulte: preg_replace - mehrfache Zeilenumbrüche "kürzen"

Hallo zusammen!

Folgendes scheint dem Archiv nach zu urteilen ein bekanntes Problem zu sein, aber ich bekomme es trotz Nachlesen nicht hin...

Ich habe ein Formular, welches eine Textarea enthält. Nehmen wir an, der Inhalt der Textarea sei in $text. Nun möchte ich, dass
(1) alle Zeilenumbrüche durch \n dargestellt werden und
(2) mehr als zwei Zeilenumbrüche hintereinander auf zwei Zeilenumbrüche "gekürzt" werden.

Mein Ansatz sieht so aus:

$text = preg_replace(  
  array(  
    '/\r\n/',  
    '/\n\r/',  
    '/\r/'  
  ), "\n", $text);  
$text = preg_replace('/\n{3,}/', "\n\n", $text);

Dabei passiert aber einfach mal gar nichts. (Ich teste übrigens mit PHP 4 unter Windows XP...)

Hat jemand eine Idee?

Viele Grüße,
Stefan

  1. Hi Stefan,

    $text = preg_replace(

    array(
        '/\r\n/',
        '/\n\r/',
        '/\r/'
      ), "\n", $text);
    $text = preg_replace('/\n{3,}/', "\n\n", $text);

      
    Sowohl \r als auch \n werden nur in <http://de3.php.net/manual/en/language.types.string.php#language.types.string.syntax.double@gigld=double quoted Strings> erkannt und in Zeilenumbrüche umgesetzt, in deinem Beispiel-Code hier verwendest du jedoch [single quoted Strings](http://de3.php.net/manual/en/language.types.string.php#language.types.string.syntax.single).  
      
      
    MfG, Dennis.
    
    -- 
    Mein SelfCode: [ie:{ fl:( br:> va:) ls:\[ fo:) rl:( n4:# ss:) de:\] js:| ch:{ sh:| mo:} zu:|](http://www.peter.in-berlin.de/projekte/selfcode/?code=ie%3A%7B+fl%3A%28+br%3A%3E+va%3A%29+ls%3A%5B+fo%3A%29+rl%3A%28+n4%3A%23+ss%3A%29+de%3A%5D+js%3A%7C+ch%3A%7B+sh%3A%7C+mo%3A%7D+zu%3A%7C)  
      
    Die [FlatBox 0.3](http://tutorial.riehle-web.com/scripts/#flatbox) mit [Dokumentation](http://tutorial.riehle-web.com/scripts/flatbox/doku.html) ist da!  
    Dies hier ist ein öffentliches Forum - wer dir hier geholfen hat, hat dies vollkommen freiwillig und unter Aufopferung seiner Freizeit getan!
    
    1. Hi,

      <http://de3.php.net/manual/en/language.types.string.php#language.types.string.syntax.double@gigld=double quoted Strings>

      Ups, da lagen wohl die Finger falsch ;-) Gemeint ist natürlich double quoted Strings

      MfG, Dennis.

      --
      Mein SelfCode: ie:{ fl:( br:> va:) ls:[ fo:) rl:( n4:# ss:) de:] js:| ch:{ sh:| mo:} zu:|
      Die FlatBox 0.3 mit Dokumentation ist da!
      Die Definition des SelfCodes ist hier zu finden, es gibt auch einen Encoder.
      1. Ups, da lagen wohl die Finger falsch ;-) Gemeint ist natürlich double quoted Strings

        Herzlichen Dank für die Antwort! Leider klappt es auch mit doppelten Anführungszeichen nicht.

        Ich hatte allerdings auch bewusst die einfachen Anführungszeichen verwendet, da ich im Kopf hatte, dass die \r und \n im regulären Ausdruck nicht schon von PHP umgesetzt werden dürfen, sondern erst von der RegEx-Engine. Ist das falsch?

        Viele Grüße,
        Stefan

        1. Hi Stefan,

          Herzlichen Dank für die Antwort! Leider klappt es auch mit doppelten Anführungszeichen nicht.

          Lies dir mal noch den Hinweis von dedlfix durch, dass es da auch systembedingte Unterschiede geben kann.

          Ich hatte allerdings auch bewusst die einfachen Anführungszeichen verwendet, da ich im Kopf hatte, dass die \r und \n im regulären Ausdruck nicht schon von PHP umgesetzt werden dürfen, sondern erst von der RegEx-Engine. Ist das falsch?

          Ja, die RegEx Maschine erkennt (AFAIK) kein \r oder \n - du kannst aber \010 bzw. \013 verwenden, auf diese Weise kannst du Zeichen direkt durch ihren numerischen Wert referenzieren. Vielleicht wäre das eine Möglichkeit, wie du die System Unterschiede auch umgehen kannst ... probier einfach mal ein bisschen herum.

          MfG, Dennis.

          --
          Mein SelfCode: ie:{ fl:( br:> va:) ls:[ fo:) rl:( n4:# ss:) de:] js:| ch:{ sh:| mo:} zu:|
          Die FlatBox 0.3 mit Dokumentation ist da!
          Wer die FAQ gelesen hat, ist klüger! ... und weiß wie man Links macht ;-)
          1. Hi Dennis!

            Herzlichen Dank für die Antwort! Leider klappt es auch mit doppelten Anführungszeichen nicht.

            Lies dir mal noch den Hinweis von dedlfix durch, dass es da auch systembedingte Unterschiede geben kann.

            Zitat von dedlfix:

            In diesem Falle sollen sie auch gar nicht von PHPs String-Parser erkannt werden, sondern an den Regulären Ausdruck durchgereicht werden. Der erkennt die Zeichen auch. (Und gelegentlich ist es auch ein Unterschied, ob man den String \n oder ein Byte mit dem Wert 10 übergibt. Ein System könnte \n in die Bytefolge 13,10 übersetzen.)

            Wenn ich das richtig verstehe ist demnach doch die Verwendung von einfachen Anführungszeichen vorzuziehen...?

            Ich hatte allerdings auch bewusst die einfachen Anführungszeichen verwendet, da ich im Kopf hatte, dass die \r und \n im regulären Ausdruck nicht schon von PHP umgesetzt werden dürfen, sondern erst von der RegEx-Engine. Ist das falsch?

            Ja, die RegEx Maschine erkennt (AFAIK) kein \r oder \n - [...]

            Siehe oben.

            Außerdem tut das ganze Konstrukt ja doch seinen Dienst, siehe:
            Beitrag von dedlfix und
            Beitrag von mir.

            Trotzdem vielen Dank für die Mühe.

            Viele Grüße,
            Stefan

    2. echo $begrüßung;

      Sowohl \r als auch \n werden nur in double quoted Strings erkannt und in Zeilenumbrüche umgesetzt, in deinem Beispiel-Code hier verwendest du jedoch single quoted Strings.

      In diesem Falle sollen sie auch gar nicht von PHPs String-Parser erkannt werden, sondern an den Regulären Ausdruck durchgereicht werden. Der erkennt die Zeichen auch. (Und gelegentlich ist es auch ein Unterschied, ob man den String \n oder ein Byte mit dem Wert 10 übergibt. Ein System könnte \n in die Bytefolge 13,10 übersetzen.)

      echo "$verabschiedung $name";

  2. echo $begrüßung;

    $text = preg_replace(

    array(
        '/\r\n/',
        '/\n\r/',
        '/\r/'
      ), "\n", $text);

      
    Hier brauchst du keine RegEx. Da reicht ein einfaches strtr() oder str\_replace().  
      
    
    > `$text = preg_replace('/\n{3,}/', "\n\n", $text);`{:.language-php}  
    > Dabei passiert aber einfach mal gar nichts.  
      
    Bist du sicher? Wie prüfst du das? Bei mir arbeitet es wie gewünscht.  
    Du kannst dir ja auch mal die Bytes des Ergebnisses (und/oder des Zwischenergebnisses) ausgeben lassen:  
      
    `echo chunk_split(bin2hex('test string'), 2, ' ');`{:.language-php}  
      
      
    echo "$verabschiedung $name";
    
    1. Hallo!

      $text = preg_replace('/\n{3,}/', "\n\n", $text);
      Dabei passiert aber einfach mal gar nichts.

      Bist du sicher? Wie prüfst du das? Bei mir arbeitet es wie gewünscht.
      Du kannst dir ja auch mal die Bytes des Ergebnisses (und/oder des Zwischenergebnisses) ausgeben lassen:

      echo chunk_split(bin2hex('test string'), 2, ' ');

      In der Tat, das funktioniert auch bei mir. Ich verwende diesen Code in einer Funktion, die wiederum als Filter in einem PEAR-QuickForm-Formular dient. Die Funktion wird auch aufgerufen, der Filter zeigt aber keine Wirkung im Formular.

      Danke für die Hilfe! Ich mach' mich mal auf die Suche nach dem Fehler. Vermutlich stimmt bei der Verwendung von QuickForm etwas nicht...

      Viele Grüße,
      Stefan

    2. Hallo,

      Hier brauchst du keine RegEx. Da reicht ein einfaches strtr() oder str_replace().

      *mmh*  wie beseitigt man mit einem str_replace() alle mehrfachen Zeilenumbrüche? Angenommen, Du hast einen fünffachen Zeilenumbruch, dann bleibt doch immer noch ein dreifacher übrig, wenn Du nur doppelte gegen einfache tauschst...

      Die Funktion alleine ist "bytesicher" und nicht rekursiv.

      Die Frage ist durchaus ernst gemeint, denn es sollte mit der Funktion str_replace() trotzdem eine einfache und elegante Lösung geben.

      LG
      Chris

      1. echo $begrüßung;

        Hier brauchst du keine RegEx. Da reicht ein einfaches strtr() oder str_replace().

        *mmh*  wie beseitigt man mit einem str_replace() alle mehrfachen Zeilenumbrüche?

        Diese Antwort bezog sich auf den ersten Teil des Codes, in dem es nur darum ging, einfache \r\n, \n\r und \r durch \n zu ersetzen.

        echo "$verabschiedung $name";

        1. Hallo Dedlfix,

          Hier brauchst du keine RegEx. Da reicht ein einfaches strtr() oder str_replace().

          *mmh*  wie beseitigt man mit einem str_replace() alle mehrfachen Zeilenumbrüche?

          Diese Antwort bezog sich auf den ersten Teil des Codes, in dem es nur darum ging, einfache \r\n, \n\r und \r durch \n zu ersetzen.

          ... was aber noch nicht die Frage nach der möglichst intelligenten Verwendung von str_replace() beantwortet...

          Wie würdest Du das geatalten?

          LG
          Chris

          1. Hallo Chris.

            ... was aber noch nicht die Frage nach der möglichst intelligenten Verwendung von str_replace() beantwortet...

            Wie würdest Du das geatalten?

            Vielleicht so?

            $text = "Hallo  
            Welt!  
            So weit  
            nichts Neues.";  
              
            $lineends = array("\r\n", "\n", "\r");  
              
            $text = str_replace($lineends, "\n", $text);
            

            Einen schönen Mittwoch noch.

            Gruß, Ashura

            1. Hallo Ashura,

              ... was aber noch nicht die Frage nach der möglichst intelligenten Verwendung von str_replace() beantwortet...

              Wie würdest Du das geatalten?

              Vielleicht so?

              $text = "Hallo

              Welt!
              So weit
              nichts Neues.";

              $lineends = array("\r\n", "\n", "\r");

              $text = str_replace($lineends, "\n", $text);

                
              So war das nicht gemeint.  
              Es ging um die Verwendung von str\_replace() zur Beseitigung mehrfacher Zeilenumbrüche, also die Reduzierung auf jeweils nur einen Zeilenumbruch in Folge.  
                
              Wenn ich alle doppelten auf einfache reduziere, was ist dann mit den dreifachen, usw.?  Also wie sorge ich dafür, dass aus "\n\n\n" nur "\n" wird und aus "\n\n" auch nur "\n" ...  
                
                
                
              LG  
              Chris  
                
              
              
              1. echo $begrüßung;

                Es ging um die Verwendung von str_replace() zur Beseitigung mehrfacher Zeilenumbrüche, also die Reduzierung auf jeweils nur einen Zeilenumbruch in Folge.

                Warum willt du dafür unbedingt str_replace() nehmen? Die preg_replace-Lösung ist für diese Aufgabe besser geeignet, da sie mit einer variablen Suchstringlänge umgehen kann, während die Länge des Suchstrings[*] bei str_replace() feststehen muss.

                Wenn es unbedingt mit str_replace() sein soll, schlage ich folgenden Zweizeiler vor:

                while (strpos($string, "\n\n\n") !== false)  
                  $string = str_replace("\n\n\n", "\n\n", $string);
                

                Bei Reduzierung auf einen Zeilenumbruch muss noch jeweils einmal \n weg.

                echo "$verabschiedung $name";

                [*] oder der Suchstrings, wenn man ein Array übergibt.