Regina Beikal: PHP: Im Sting nach Komma suchen die sich in Klammern befinden

Hallo,

ich falle direkt mit der Tür ins Haus. Bei einem String sollen die Kommas innerhalb von Klammern gegen Plus Symbole ersetzt werden.

Bsp. String ist:

$bsp_string = "Lorem ipsum dolor sit amet, consetetur sadipscing (elitr, sed diam nonumy eirmod tempor invidunt, ut labore, et dolore magna aliquyam erat), (sed diam) voluptua. (At, vero) eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.";

Bsp. String soll:

$bsp_string = "Lorem ipsum dolor sit amet, consetetur sadipscing (elitr+ sed diam nonumy eirmod tempor invidunt+ ut labore+ et dolore magna aliquyam erat), (sed diam) voluptua. (At+ vero) eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.";

Ich kenne die Funktion "str_replace" diese (sofern ich es richtig verstanden habe) ist nur generell einsetzbar. Welche Möglichkeiten habe ich alternativ?

  1. @@Regina Beikal

    Bei einem String sollen die Kommas innerhalb von Klammern gegen Plus Symbole ersetzt werden.

    Wenn es nicht mehrere Klammerebenen gibt, sollte es gehen, ( gefolgt von beliebeigen Zeichen außer ) und , gefolgt von , zu ersetzen durch ( gefolgt von den ebendiesen beliebigen Zeichen gefolgt von +.

    Also \(([^),]*), ersetzen durch ($1+.

    LLAP 🖖

    --
    Ist diese Antwort anstößig? Dann könnte sie nützlich sein.
    1. Hi,

      Also \(([^),]*), ersetzen durch ($1+.

      bei bla(x,y,z)blubb ersetzt das aber auch nur das , nach dem x, denn für das zweite Match wird erst hinter dem ersten Match angefangen, dort findet sich aber keine öffnende Klammer mehr ...

      Eine Lösung per Regex erscheint mir schwierig.

      Ich würde das vermutlich so lösen:

      ersetze = 0;
      Zeichenweise durchlaufen durch den String
        falls aktuellesZeichen == '(' setze ersetze++;
        sonst falls aktuellesZeichen == ')' und ersetze > 0 setze ersetze-- 
        sonst falls aktuellesZeichen == ',' und ersetze > 0, setze aktuellesZeichen = '+'
        schreibe aktuellesZeichen in den Ausgabestring
      

      cu,
      Andreas a/k/a MudGuard

  2. Hallo Regina Beikal,

    Für solche allgemeinen Suchmuster bieten sich reguläre Ausdrücke an. In PHP preg_replace

    Dein Suchmuster könnte so aussehen

    /\(.*\,.*\)/
    

    Dabei bedeuten / Stringanfang bzw. Ende, \( die öffnende Klammer, die maskiert werden muss, .* kein oder beliebig viele beliebige Zeichen. Um das Komma zum Ersetzen zu bestimmen, muss es in Klammern gesetzt werden, also:

    /\(.*(\,).*\)/
    

    ungetestet

    Bis demnächst
    Matthias

    --
    Signaturen sind bloed (Steel) und Markdown ist mächtig.
    1. Hallo Matthias,

      Dabei bedeuten / Stringanfang bzw. Ende

      Nein. Die Slashes sind nur der Delimiter für die Regex-Engine. Hintergrund: die preg-Funktionen benutzen Perl-Regexe, und dort sind reguläre Ausdrücke direkt im Code eingebettet und mit Delimitern davon abgegrenzt. Meistens ist das //, prinzipiell kann aber ein beliebiges Zeichen benutzt werden. Das ist dann wichtig, wenn Klammern benutzt werden, denn dann muss man eine schliessende Klammer angeben um den Regex zu beenden: preg_match("(abc)", "aouaoeu abc auaoeu");

      Stringanfang bzw -ende entsprechen den Ankern \A und \z. Nein, ^ und $ sind nicht zwangsläufig Stringanfang bzw -ende.

      LG,
      CK

    2. Hi,

      Für solche allgemeinen Suchmuster bieten sich reguläre Ausdrücke an. In PHP preg_replace

      Dein Suchmuster könnte so aussehen

      /\(.*\,.*\)/
      

      Dabei bedeuten / Stringanfang bzw. Ende,

      Das hat Christian ja schon erklärt.

      \( die öffnende Klammer, die maskiert werden muss,

      .* kein oder beliebig viele beliebige Zeichen.

      Und das ist falsch.

      Denn das würde auch bla) matchen, so daß das nachfolgende , nicht in der Klammer steht - in Verbindung mit dem zweiten .*, das auch (bla matchen würde ... Wenn, dann müßte hier ungreedy gesucht werden, also mit .*?.

      Das hätte dann aber immer noch das Problem, das pro Durchgang nur 1 Komma pro Klammer gefunden würde, es müßte also in einer Schleife so lange ersetzt werden, bis der Ergebnisstring dem vorherigen entspricht.

      Um das Komma zum Ersetzen zu bestimmen, muss es in Klammern gesetzt werden,

      Nein.

      Im Ersetzungsstring werden die beiden variablen Teile (bei Dir .*) wieder benötigt, um sie in den Ergebnisstring wieder einsetzen zu können, also müssen diese beiden geklammert werden.

      ungetestet

      und nicht funktionierend.

      cu,
      Andreas a/k/a MudGuard

  3. Hallo!

    Bei einem String sollen die Kommas innerhalb von Klammern gegen Plus Symbole ersetzt werden.

    Das kannst du z.B. mit regex preg_replace() machen.

    Um die Kommas innerhalb von Klammern zu finden, benoetigst du einen sog. Lookahead:

    $str = preg_replace('/,(?=[^(]*\))/', "+", $str);
    

    (?= leitet einen sog. positiven Lookahead ein. Dabei handelt es sich um eine zero width assertion. Es werden vom regex Parser keine Zeichen "konsumiert" sondern genau an der Stelle nach vorne geguckt, ob eine bestimmte Bedingung zutrifft.

    Die Bedingung [^(]*\) es muessen beliebig viele Zeichen kommen, die keine oeffnende Klammer sind, gefolgt von einer schliessenden Klammer. [^ leitet eine negierte Zeichenklasse ein. Der Stern * dient als sog. Quantifier fuer 0 oder mehr.

    Du kannst das Suchmuster hier probieren oder hier ein PHP Beispiel.

    Viel Erfolg, Jonny 5

    1. Danke,

      das war die beste Antwort. Vielen Dank für die tolle Erklärung.

      Hallo!

      Bei einem String sollen die Kommas innerhalb von Klammern gegen Plus Symbole ersetzt werden.

      Das kannst du z.B. mit regex preg_replace() machen.

      Um die Kommas innerhalb von Klammern zu finden, benoetigst du einen sog. Lookahead:

      $str = preg_replace('/,(?=[^(]*\))/', "+", $str);
      

      (?= leitet einen sog. positiven Lookahead ein. Dabei handelt es sich um eine zero width assertion. Es werden vom regex Parser keine Zeichen "konsumiert" sondern genau an der Stelle nach vorne geguckt, ob eine bestimmte Bedingung zutrifft.

      Die Bedingung [^(]*\) es muessen beliebig viele Zeichen kommen, die keine oeffnende Klammer sind, gefolgt von einer schliessenden Klammer. [^ leitet eine negierte Zeichenklasse ein. Der Stern * dient als sog. Quantifier fuer 0 oder mehr.

      Du kannst das Suchmuster hier probieren oder hier ein PHP Beispiel.

      Viel Erfolg, Jonny 5

    2. @@Jonny 5

      Um die Kommas innerhalb von Klammern zu finden, benoetigst du einen sog. Lookahead:

      Das glaube ich nicht. Es sollte auch mit regulären Ausdrücken möglich sein.

      LLAP 🖖

      --
      Ist diese Antwort anstößig? Dann könnte sie nützlich sein.
      1. @@Jonny 5

        Um die Kommas innerhalb von Klammern zu finden, benoetigst du einen sog. Lookahead:

        Das glaube ich nicht. Es sollte auch mit regulären Ausdrücken [möglich]

        Womit du das erste Komma innerhalb der Klammern gegen ein Plus ersetzen wuerdest. Natuerlich kann man das wiederholen bis alle weg sind. Eine Alternative waere die Verwenung von \G (am vorangehenden Treffer anschliessen) und \K (Anfang des bereits gematchten resetten)

        (?:\([^),]*|\G(?!^))\K,([^),]*)
        

        Und ersetzten mit +$1 siehe regex101

        Das ist aber fuer jemanden der noch nicht viel mit regex zu tun hatte schwieriger zu verstehen.

        1. Es sollte auch ohne capture group funktionieren

          $str = preg_replace('/(?:\(|\G(?!^))[^,)]*\K,/', "+", $str);
          

          Finde aber die Lookahead Loesung die einfachste und kompatibelste.

          Naja, fand es interessant. Einen schoenen Abend!

    3. Hi,

      $str = preg_replace('/,(?=[^(]*\))/', "+", $str);
      

      Da fehlt noch ein g.

      Außerdem klappt's nicht bei sowas: bla,blubb (x,(a,b),z) blubb.bla

      cu,
      Andreas a/k/a MudGuard

      1. Da fehlt noch ein g.

        Die Frage war zu PHP da gibt's kein global flag, falls du das meinst.

        Außerdem klappt's nicht bei sowas: bla,blubb (x,(a,b),z) blubb.bla

        Das war nicht die Frage. Dazu koennte man preg_replace_callback mit rekursivem regex verwenden.

      2. Außerdem klappt's nicht bei sowas: bla,blubb (x,(a,b),z) blubb.bla

        Etwas in der Art:

        $str = preg_replace_callback('/\((?>[^)(]+|(?R))*\)/', function($m) {
          return str_replace(",", "+", $m[0]);
        }, $str);
        

        Siehe eval.in oder regex101 Suchmuster

  4. Auch wenns mich nüscht angeht: Wozu soll das denn gut sein?

    -Alfred