finswimmer: Text an mehreren Positionen im String einfügen

Hallo,

ich habe eine Zeichenkette bei der ich an mehreren Positionen eine Auszeichnung mittels <span> einfügen will.

Aus z.B.

ggatcttgctccagatttgc

soll werden

g<span class="seqinfo">g</span>atctt<span class="seqinfo">g</span>ctccagatttgc

Die Anzahl der Einfügungen kann variieren. Umspannen tut das span jeweils nur einen Buchstaben. Die Positionen an denen ausgezeichnet werden soll liegen in einem array vor.

Bisher baue ich den String Zeichen für Zeichen neu auf und füge das <span> an entsprechender Stelle dabei ein.

Das funktioniert wie gewünscht. Dennoch stellt sich mir die Frage ob es nicht eine elegantere/bessere/schnellere Lösung in PHP dafür gibt?

fin swimmer

akzeptierte Antworten

  1. Hallo,

    Das funktioniert wie gewünscht. Dennoch stellt sich mir die Frage ob es nicht eine elegantere/bessere/schnellere Lösung in PHP dafür gibt?

    PHP kann innerhalb eines Strings Zeichenketten ersetzen.

    Gruß
    Kalk

    1. Hallo Kalk,

      PHP kann innerhalb eines Strings Zeichenketten ersetzen.

      ja diese Funktion war mir durchaus bekannt. Ich wusste nur nicht wie ich sie anwenden soll, wenn ich mehrere Einfügungen durchführen will, da sich ja mit jedem Einfügen die Stringlänge und damit der Index an dem eingefügt werden soll ändert.

      Der Trick besteht nun darin, die Einfügungen in einer Schleife vom Ende des Strings angefangen durchzuführen. Dadurch verändert sich der Index der davorliegenden Zeichen nicht.

      Viele Grüße,

      Tobias

  2. Bisher baue ich den String Zeichen für Zeichen neu auf und füge das <span> an entsprechender Stelle dabei ein.

    Wieviel Zeilen Code sind das?

    Habe hier mal eine kleine Fingerübung. Ich markiere die gewünschten Positionen im String durch ein Zeichen, das im Text nicht vorkommen kann:

      $pos = array( 5, 9, 12, 16, 21 );  // 5 Positionen
      $alt = 'qwertzuiopasdfghjklxcvbnm,';
      //     '----.----1----.----2----.----3' nur Zeiger
      $zeichen = '';
    
      for ( $i=0; $i<count($pos); $i++ ) {
        $zeichen .= $alt[$pos[$i]-1];
        $alt[$pos[$i]-1] = '_';
      }
      $arr = explode( "_", $alt ); // 6 Teilstrings
      $neu = '';
      for ( $i=0; $i<=count($pos); $i++ ) {
        $neu  .= $arr[$i];
        if ( $i<count($pos) ) $neu .= "<u>".$zeichen[$i]."</u>";
      }
      echo "<pre>[".$neu."]</pre>";
    

    Linuchs

    1. Hi,

      Wieviel Zeilen Code sind das?

      Wenn es um die Anzahl der Zeilen geht, geht's kürzer:

      $pos = array( 5, 9, 12, 16, 21 );  // 5 Positionen
      $text = 'qwertzuiopasdfghjklxcvbnm,';
      for ($i = count($pos) - 1; $i >= 0; $i--) {
          $text = preg_replace("~(?<=^.{".$pos[$i]."})(.)~", 
                               "<span class=\"seqinfo\">$1</span>", $text);
      }
      

      ungetestet mangels greifbarem PHP-Interpreter, kann auch noch Syntax-Fehler enthalten ...

      Je nachdem, ob die Positionen 0 oder 1 als Basis haben, muß ggf. noch ein -1 bei der Position gemacht werden.

      cu,
      Andreas a/k/a MudGuard

    2. Wieviel Zeilen Code sind das?

      Das geht schon noch. Ich hatte eher Performancebedenken, da ich so ja jedes einzelne Zeichen durchgehe.

      $pos = array( 5, 9, 12, 16, 21 );  // 5 Positionen
      $alt = 'qwertzuiopasdfghjklxcvbnm,';
      $neu = '';
      
      for ($i=0; $i < strlen($alt); $i++) {
          if (in_array($i, $pos)) {
              $neu .= '<span class="varpos">'.substr($alt, $i, 1).'</span>';
          } else {
              $neu .= substr($alt, $i, 1);
          }
      }
      

      Meine jetztige Lösung finde ich irgendwie schöner:

      $pos = array( 5, 9, 12, 16, 21 );  // 5 Positionen
      $sequence= 'qwertzuiopasdfghjklxcvbnm,';
      
      for ($i = count($pos)-1; $i >= 0; $i--) {
          $sequence = substr_replace($sequence, "</span>", $pos[$i]+1, 0);
          $sequence = substr_replace($sequence, '<span class="varpos">', $pos[$i], 0);
      }
      

      finswimmer

      1. Das geht schon noch. Ich hatte eher Performancebedenken, da ich so ja jedes einzelne Zeichen durchgehe.

        Immer erst bei Bedarf optimieren, nie vorab. Kümmere dich an erster Stelle um sauberen, wartbaren Code. Außerdem: wenn Du Bedenken hast, dann solltest Du messen. Dein 20-Zeichen String ist dafür allerdings zu klein. Mach mal ne große Menge draus und dann die Zeit messen. Ich bin mir ziemlich sicher, dass die RegExp-Variante bei hinreichend langen Strings sogar langsamer sein wird. Außerdem:

        $pos = array( 5, 9, 12, 16, 21 );  // 5 Positionen
        $alt = 'qwertzuiopasdfghjklxcvbnm,';
        $neu = '';
        
        for ($i=0; $i < strlen($alt); $i++) {
            if (in_array($i, $pos)) {
                $neu .= '<span class="varpos">'.substr($alt, $i, 1).'</span>';
            } else {
                $neu .= substr($alt, $i, 1);
            }
        }
        

        Schaut mir nach einer sauberen und klaren Lösung der Aufgabenstellung aus. Gut so.

        Meine jetztige Lösung finde ich irgendwie schöner:

        $pos = array( 5, 9, 12, 16, 21 );  // 5 Positionen
        $sequence= 'qwertzuiopasdfghjklxcvbnm,';
        
        for ($i = count($pos)-1; $i >= 0; $i--) {
            $sequence = substr_replace($sequence, "</span>", $pos[$i]+1, 0);
            $sequence = substr_replace($sequence, '<span class="varpos">', $pos[$i], 0);
        }
        

        Deutlich schlechter, weil dramatisch weniger intuitiv lesbar. Die Lösung ist nerdiger und vermutlich langsamer. Außerdem:

        Some people, when confronted with a problem, think "I know, I'll use regular expressions." Now they have two problems.

        1. Hallo,

          Dein 20-Zeichen String ist dafür allerdings zu klein. Mach mal ne große Menge draus und dann die Zeit messen.

          das ist mir klar. Beim jetzigen Anwendungsfall dieser Funktion wird es allerdings bei 20-30 Zeichen Strings bleiben. Je nach dem wie sich das Projekt entwickelt, komme ich aber an einen Punkt wo der String mehrere Tausend Zeichen besitzt und davon sollen mehrere Hundert ausgezeichnet werden.

          Some people, when confronted with a problem, think "I know, I'll use regular expressions." Now they have two problems.

          Der Spruch ist mir bekannt. Nicht bekannt dagegen war mir, dass PHP bei einem substr_replace RegEx bemüht.

          Meine grundsätzliche Überlegung war, dass es doch weniger Rechenzeit kosten sollte, wenn ich nur die Positionen die ausgezeichnet werden sollen durchgehe anstatt des ganzen Strings.

          finswimmer

        2. $pos = array( 5, 9, 12, 16, 21 );  // 5 Positionen
          $sequence= 'qwertzuiopasdfghjklxcvbnm,';
          
          for ($i = count($pos)-1; $i >= 0; $i--) {
              $sequence = substr_replace($sequence, "</span>", $pos[$i]+1, 0);
              $sequence = substr_replace($sequence, '<span class="varpos">', $pos[$i], 0);
          }
          

          Ersetzen wir das durch:

          $pos = array( 5, 9, 12, 16, 21 );  // 5 Positionen
          $sequence= 'qwertzuiopasdfghjklxcvbnm,';
          
          for ($i = count($pos)-1; $i >= 0; $i--) {
              $sequence = substr($sequence, 0, $pos[$i])
                          .'<span class="varpos">'
                          .substr($sequence, $pos[$i], 1)
                          ."</span>"
                          .substr($sequence, $pos[$i]+1);
          }
          

          Damit sollten wir RegEx los sein. Und lesbarer ist es auch. Oder?

          fin swimmer

          1. Damit sollten wir RegEx los sein. Und lesbarer ist es auch. Oder?

            Ich persönlich fand Deine initiale Lösung am schönsten lesbar :-)