Gerd: Problem mit RegEx und Ersetzen

Hallo, ich habe seit zwei Stunden ein RegEx-Ersetzungsproblem.

Innerhalb eines Textes $text können mehrfach Zeichenfolgen innerhalb einer öffnenden und schliessenden geschweiften Klammer auftauchen:

... {Berlin, Bremen} .... {Rom - Pisa} .... {Castrop<br> Rauxel} ...

Sofern innerhalb der geschweiften Klammern jedoch eine bestimmte Zeichenfolge, z.B. <br> auftaucht, soll <br> ersatzlos gelöscht werden, und zwar jedesmal. Aus der obigen Zeile soll also werden:
... {Berlin, Bremen} .... {Rom - Pisa} .... {Castrop Rauxel} ...

Meine Anweisung haut jedoch nicht hin:

$text =~ s/{(.*?)<br>(.*?)}/{$1$2}/g;

Oder genauer: das haut nur hin, wenn in $text eine einzige Zeichenfolge der Art
{xyz <br> xyz}
auftaucht, sobald dort mehrere stehen klappt es nicht mehr.
Aber wieso? Ich habe doch ein "g" hinter die Ersetzungs-Anweisung drangehängt?
Bin ziemlich ratlos, mache ich einen Denkfehler?

  1. gudn tach!

    $text =~ s/{(.*?)<br>(.*?)}/{$1$2}/g;

    Oder genauer: das haut nur hin, wenn in $text eine einzige Zeichenfolge der Art
    {xyz <br> xyz}
    auftaucht, sobald dort mehrere stehen klappt es nicht mehr.

    doch, sollte es.

    Aber wieso?

    minimiere mal dein beispiel auf wenige zeilen, die das problem noch immer hervorrufen und poste dann diesen code. (das letzte mal, als ich das geschrieben habe, kam der fragesteller selbst auf die antwort.)

    prost
    seth

    1. gudn tach!

      $text =~ s/{(.*?)<br>(.*?)}/{$1$2}/g;

      Oder genauer: das haut nur hin, wenn in $text eine einzige Zeichenfolge der Art
      {xyz <br> xyz}
      auftaucht, sobald dort mehrere stehen klappt es nicht mehr.

      doch, sollte es.

      noe, siehe andere antworten. in einigen faellen klappt es, in vielen aber nicht.

      minimiere mal dein beispiel auf wenige zeilen, die das problem noch immer hervorrufen und poste dann diesen code.

      noe, das passt hier nicht. aber die spezifikationen des OP sollten genauer sein. koennen z.b. wie Skeeve vermutete auch mehrere "<br>" innerhalb eines klammer-ausdruckes stehen? koennen evtl. leerzeichen in "foo<br>bar" fehlen (->"foobar", statt vielleicht besser(?) "foo bar")? naja, und solche genauigkeiten sollten halt vorher geklaert werden.

      s/({[^}]*)<br>([^}]*})/$1$2/g;

      sollte in den faellen, in denen nur max. ein "<br>" vorkommen kann, genuegen. voraussetzung ist z.b., dass die klammersetzung der {} nicht zu kompliziert ist.

      prost
      seth

  2. ... {Berlin, Bremen} .... {Rom - Pisa} .... {Castrop<br> Rauxel} ...

    [...]

    $text =~ s/{(.*?)<br>(.*?)}/{$1$2}/g;

    Dein Ausdruck sucht die erste öffnende Klammer im Text, und von dort an
    das nächste "<br>" - so eines vorhanden ist; in Deinem Beispiel ersetzt
    Du also nicht "{Castrop<br> Rauxel}" durch "{Castrop Rauxel}" sondern
    "... {Berlin, Bremen} .... {Rom - Pisa} .... {Castrop<br> Rauxel}"
    durch "... {Berlin, Bremen} .... {Rom - Pisa} .... {Castrop Rauxel}".

    Besser wäre es, Du ersetzt "(.*?)" durch ein diskriminierendes Fragment,
    zum Beispiel, indem Du dort nur Zeichen zuläßt, die innerhalb der
    Klammern stehen können, oder die ausschließt, welche dort nicht stehen
    dürfen.

    1. das nächste "<br>" - so eines vorhanden ist; in Deinem Beispiel ersetzt
      Du also nicht "{Castrop<br> Rauxel}" durch "{Castrop Rauxel}" sondern
      "... {Berlin, Bremen} .... {Rom - Pisa} .... {Castrop<br> Rauxel}"
      durch "... {Berlin, Bremen} .... {Rom - Pisa} .... {Castrop Rauxel}".

      Hrm - was der Ausdruck findet, fängt, wie im Text erwähnt, natürlich
      direkt mit der geschweiften Klammer an, und nicht mit "... {".

      Wenn Du übrigens mehrere "<br>"s innerhalb der Klammern ersetzen willst,
      (habe Deinen Beitrag bei nochmaligem Lesen auch so deuten können) wäre
      wohl der Einsatz von Lookarounds (oder mehrere Einzelschritte) nötig;
      so etwas in der Art von: /(?<=[{>])([^<}]*)<br>(?=[^{}]*})/ -> '$1'.

  3. Moin!

    Das funktioniert aus mehreren Gründen nicht. Zum einen erfaßt Du mit Deinem .*? schon zuviel, zum anderen mußt Du den Ausdruck mehrfach laufen lassen, da Du bei einem (vereinfachte Darstellung) Ausdruck /{.*?</ im String "{ xxx <br> <br>" nach der ersten Ersetzung bereits den Teil ""{ xxx <br>" abgearbeitet hast und das zweite <br> keine öffnedne Klammer mehr findet.

    Hier ein Script das es in vielen Fällen tut:

    #!/usr/bin/perl  
      
    use strict;  
    use warnings;  
      
    while (<DATA>) {  
     1 while s/(\{[^}<]*)<[^}>]*>(?=[^}]*\})/$1/g;  
     print;  
    }  
      
    __DATA__  
    OK: {Berlin, Bremen} .... {Rom - Pisa} .... {Castrop<br> Rauxel} ..  
    OK: {Berlin, Bremen} .... {Rom - Pisa} .... {Castrop<br> <br>Rauxel} ..  
    OK: {Berlin, Bremen} .... {Rom <br> Pisa} .... {Castrop<br> Rauxel} ..  
    OK: {Berlin, <br> Bremen} .... {Rom <br><br> Pisa} .... {Castrop<br> Rauxel} ..  
    OK: {Berlin, Bremen<br>} .... {Rom - Pisa} .... {Castrop<br> Rauxel} ..  
    NICHT OK 1a:{Berlin, Bremen} .... {Rom - Pisa} .... {Castrop<br>  
    NICHT OK 1b:Rauxel} ..  
    NICHT OK 2a:{Berlin, Bremen} .... {Rom - Pisa} .... {Castrop<br  
    NICHT OK 2b:>Rauxel} ..  
    
    

    -- Skeeve

    1. Moin!

      Hier eine Variante die mit den Umbrüchen klarkommt, vorausgesetzt, Du kannst damit leben, daß die gesamten Daten auf einmal in den Speicher geladen werden dürfen (Die 3 Zeilen bei "SLURP:".

      Zudem spare ich das mehrfache abarbeiten desselben Strings indem er erstmal in Gruppen (mit Klammern / ihne Klammern) geteilt wird (split) und die mit Klammern (jede 2te/ungerade) einfach von allen <...> befreit wird.

      #!/usr/bin/perl  
        
      use strict;  
      use warnings;  
        
      SLURP: { local $/;  
       $_= <DATA>;  
      }  
      my $odd=1;  
      foreach ( split /(\{[^}]*\})/s ) {  
       if ( $odd= 1-$odd ) {  
        s/<[^>]*>//g;  
       }  
       print;  
      }  
        
      __DATA__  
      OK: {Berlin, Bremen} .... {Rom - Pisa} .... {Castrop<br> Rauxel} ..  
      OK: {Berlin, Bremen} .... {Rom - Pisa} .... {Castrop<br> <br>Rauxel} ..  
      OK: {Berlin, Bremen} .... {Rom <br> Pisa} .... {Castrop<br> Rauxel} ..  
      OK: {Berlin, <br> Bremen} .... {Rom <br><br> Pisa} .... {Castrop<br> Rauxel} ..  
      OK: {Berlin, Bremen<br>} .... {Rom - Pisa} .... {Castrop<br> Rauxel} ..  
      NICHT OK 1a:{Berlin, Bremen} .... {Rom - Pisa} .... {Castrop<br>  
      NICHT OK 1b:Rauxel} ..  
      NICHT OK 2a:{Berlin, Bremen} .... {Rom - Pisa} .... {Castrop<br  
      NICHT OK 2b:>Rauxel} ..  
      
      

      -- Skeeve

  4. Vielen Dank an Skeeve, oriberu und seth für die Tipps!
    Es klappt jetzt!

    Vielleicht noch kurz zum Hintergrund meiner Frage: In einem eigenen Script für ein kleines Online-Redaktionssystem passiert es ab und zu, dass in der text-area eines Formularfeldes mitten im Text innerhalb  eines Links ein Zeilenvorschub eingebaut wird oder sogar mehrere. Also z.B.:

    <a href="http://www.url.de"
    target="_blank">Dies ist jetzt ein sehr langer ............
    Seitenname</a>

    Zeilenvorschübe im Text sind okay, im Link nicht, deshalb will ich sie mit der Ersetzung rausnehmen.