Klaus1: Zeichen in String eins höher zählen funktioniert nicht. Warum?

Hallo,

ich bin schon fast am Verzweifeln...

In dem String "QMF 71328_C Test" möchte ich aus dem "C" ein "D" machen und dann in eine MySQL-Tabelle speichern.

Mein erster Versuch war:

$string = "QMF 71328_C Test";
$rev = substr($string,10,1);
$next_rev = ++$rev;
$string[10] = $next_rev;
$sql = "update tabelle set titel = '$string' where id = '123'";

In der Tabelle wird aber "Array" gespeichert. Nächster Versuch mit $string = strval($string); machte keinen Unterschied. Neuer Versuch mit

$string = substr_replace($string,$next_rev,10,1);

schreibt jetzt einen Leerstring in die Tabelle.

Wenn ich den Code in einer Sandbox teste, funktioniert alles einwandfrei.

Wo ist denn bloß mein Fehler?

LG Klaus

  1. Hallo,

    hat sich erledigt. Ich habe den Fehler gefunden. Er lag (natürlich) nicht an dem Code zum Hochzählen des Index, sondern vorher schon an der Ermittlung des Strings.

    Danke trotzdem.

    LG Klaus

  2. ich bin schon fast am Verzweifeln...

    Das wirst Du bals wieder sein - oder jemand anderes.

    In dem String "QMF 71328_C Test" möchte ich aus dem "C" ein "D" machen und dann in eine MySQL-Tabelle speichern.

    Mein erster Versuch war:

    $string = "QMF 71328_C Test";
    $rev = substr($string,10,1);
    $next_rev = ++$rev;
    $string[10] = $next_rev;
    $sql = "update tabelle set titel = '$string' where id = '123'";
    

    Offensichtlich willst Du einfach das nächste Zeichen der ASCII-Tabelle nehmen. Das gänge als Einzeiler.

    $string[10] = chr( 1 + ord( $string[10] ) );
    

    Ich markiere das als „schlechten Code“, denn die ganze Methode bereitet mir Kopfschmerzen, die hat keine Zukunft:

    <?php
    # Nicht nachmachen!
    $string = "QMF 71328_C Test";
    for ( $i = 0; $i < 100; $i++) {
    	$string[10] = chr( 1 + ord( $string[10] ) );
    	echo $string.PHP_EOL;
    }
    

    Ergebnisse (Auswahl)

    …
    
    0 : QMF 71328_D Test
    1 : QMF 71328_E Test
    2 : QMF 71328_F Test
    …
    22 : QMF 71328_Z Test
    23 : QMF 71328_[ Test
    24 : QMF 71328_\ Test
    …
    29 : QMF 71328_a Test
    30 : QMF 71328_b Test
    31 : QMF 71328_c Test
    …
    54 : QMF 71328_z Test
    55 : QMF 71328_{ Test
    …
    60 : QMF 71328_� Test
    61 : QMF 71328_� Test
    …
    188 : QMF 71328_ Test
    189 : QMF 71328_ Test
    190 : QMF 71328_ Test
    191 : QMF 71328_ Test
    192 : QMF 71328_ Test
    193 : QMF 71328_ Test
    194 : QMF 71328_ Test
    195 : QMF 71328_ Test
    196 : QMF 71328 Test
    197 : QMF 71328_	 Test
    198 : QMF 71328_
     Test
    199 : QMF 71328_
                     Test
    200 : QMF 71328_
                     Test
     Test QMF 71328_
    …
    221 : QMF 71328_! Test
    222 : QMF 71328_" Test
    …
    236 : QMF 71328_0 Test
    237 : QMF 71328_1 Test
    …
    245 : QMF 71328_9 Test
    246 : QMF 71328_: Test
    247 : QMF 71328_; Test
    …
    252 : QMF 71328_@ Test
    253 : QMF 71328_A Test
    254 : QMF 71328_B Test
    255 : QMF 71328_C Test
    256 : QMF 71328_D Test
    …
    

    DAS wirst Du nicht wollen, Dein Auftraggeber wohl auch nicht. Bevor das aufscheinende Problem aus Sicht des Programmierers gelöst werden kann muss es eine bessere Vorschrift

    1. für den Aufbau des Strings und
    2. für die Ermittlung des Kennzeichens der "neuen Version" (Bei Dir war das "C"→"D") geben.
    1. Level 9

      Zitat:

      In diesem Zusammenhang nutzen der Kryptoexperte Bruce Schneier und die Netzwerksicherheitsfirma RSA den Begriff. In einem Kommentar im RSA-Blog vom 7. Dezember 2010 erweiterte der Gastautor Ian Farquhar das Netzwerkmodell um Layer 8 und noch zwei weitere Layer.

      Das gesamte erweiterte OSI-Modell sieht dann wie folgt aus:

      • Layer 8: das Individuum (Human Layer)
      • Layer 9: die Organisation (Organization Layer)
      • Layer 10: der Staat (Legal and External Compliance Layer)
    2. Hallo,

      Ich markiere das als „schlechten Code“, denn die ganze Methode bereitet mir Kopfschmerzen, die hat keine Zukunft:

      Gut, dass du deinen eigenen Code so markierst. Möglicherweise hat Klaus mit Absicht den Increment-Operator verwendet, der die aufgezeigten Probleme offenbar nicht hat.

      Bevor das aufscheinende Problem aus Sicht des Programmierers gelöst werden kann muss es eine bessere Vorschrift

      1. für den Aufbau des Strings und
      2. für die Ermittlung des Kennzeichens der "neuen Version" (Bei Dir war das "C"→"D") geben.

      Das ist natürlich sinnvoll.

      Gruß
      Kalk

      1. . Möglicherweise hat Klaus mit Absicht den Increment-Operator verwendet, der die aufgezeigten Probleme offenbar nicht hat.

        Mag sein. Aber eine echte Verbesserung tritt nicht ein, bzw. bleibt es bei minestens der aufgezeigten Probleme:

        <?php
        $string = "QMF 71328_C Test";
        for ( $i = 0; $i < 257; $i++) {
        	$rev = substr($string,10,1);
        	$next_rev = ++$rev;
        	$string[10] = $next_rev;
        	echo "$i : $string" . PHP_EOL;
        }
        
        0 : QMF 71328_D Test
        1 : QMF 71328_E Test
        …
        23 : QMF 71328_A Test
        24 : QMF 71328_B Test
        25 : QMF 71328_C Test
        26 : QMF 71328_D Test
        …
        48 : QMF 71328_Z Test
        49 : QMF 71328_A Test
        50 : QMF 71328_B Test
        51 : QMF 71328_C Test
        52 : QMF 71328_D Test
        53 : QMF 71328_E Test
        …
        

        Aus gutem Grund nehme ich nämlich an, dass die Versionisierung ein[ein]deutig sein soll.

        1. Eine mögliche Lösung könnte dann so aussehen:

          <?php
          $string = "QMF 71328_C Test";
          for ( $i = 0; $i < 257; $i++) {
          	list( $p1, $p2 ) = explode( '_', $string, 2 );
          	list( $p2, $p3 ) = explode( ' ', $p2, 2 );
          	$next_p2 = ++$p2;
          	$string = $p1.'_'.$next_p2.' '.$p3;
          	echo "$i : $string" . PHP_EOL;
          }
          

          Ausgaben:

          …
          22 : QMF 71328_Z Test
          23 : QMF 71328_AA Test
          …
          48 : QMF 71328_AZ Test
          49 : QMF 71328_BA Test
          …
          
          1. Hallo Raketentheo,

            ich hatte gedacht, mit preg_replace_callback könnte es einfacher sein, aber ist es das wirklich? 🤔

            $string = "QMF 71328_X Test";
            
            for ($i=0; $i<10; $i++)
            {
              $string = preg_replace_callback(
                  "/_(.*?) /",
                  function($treffer) { return "_" . ++$treffer[1] . " "; },
                  $string);
              echo "$i - nächster Schritt ist $string \n";
            }
            

            Rolf

            --
            sumpsi - posui - obstruxi
            1. aber ist es das wirklich? 🤔

              Kommt drauf an, für wen und für was. 😛

  3. Hallo,

    TIL: PHP kann Strings inkrementieren 😲.

    Und wiedermal erweist sich: PHP kann alles, aber nichts richtig.

    $a = "123_Z";
    $b = "123Z";
    $c = "Z";
    
    ++$a;
    ++$b;
    ++$c;
    
    echo "$a \n";    // 123_A
    echo "$b \n";    // 124A
    echo "$c \n";    // AA
    

    Man kann für jede einzelne der gezeigten Verhaltenweisen gute Gründe finden, aber jede Ausnahme mehr, die man beachten muss, macht es chaotischer.

    Rolf

    --
    sumpsi - posui - obstruxi
    1. "123_Z" -> "123_A" (erwartet hätte ich "123_AA")
      "123Z"  -> "124A"  (erwartet hätte ich "123AA")
      

      ... "geht gar nicht". Aus dem Grund ist das Inkrementieren von Strings in PHP nicht das, was ich empfehlen würde.

      Da fällt mir aber ein, ich habe vor Jahren mal was zu kruden Zahlensystemen implementiert.

      <?PHP
      $NS = new numberSystem('ABCDEFGHIJKLMNOPQRSTUVWXYZ');
      
      $s='A';
      echo $s . PHP_EOL;
      for($i=0; $i<100; $i++) {
         $s = $NS->getString( 1 + $NS->getDec( $s ) );
         echo $s . PHP_EOL;
      }
      
      class numberSystem
      {
          protected $arChars = false;
          protected $hash = false;
       
          function __construct($var='niceReadable32') {
              switch (true) {
                  case ( is_array($var) ):
                      return setChars( $var );
                  case ( 'bin' == $var || 'binär' == $var ):
                      $this -> setChars (  array('0','1') );
                      break;
                  case ( 'alphabet' == $var || 'alpha' == $var ):
                      $this -> setChars ('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ');
                      break;
                  case ( 'ascii_33_126' == $var || 'ascii_visible' == $var ):
                      $ar = array();
                      for ($i=33; $i<127; $i++) { $ar[] = chr($i); }
                      $this -> setChars($ar);
                      break;
                  case( 'niceReadable32' == $var ):
                      $this -> setChars ( array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','J','K','L','M','N','P','R','S','T','U','V','W','X','Y','Z') );
                      break;
                  case( 'decObusfacted' == $var || 'wuerfel' == $var ):
                      $this -> setChars ( array('0','9','8','7','1','2','3','5','4','6') );
                      break;
                  default:
                      $this -> setChars ( $var );
                      break;
              }
              return true;
          }
       
          public function getChars() {
              return $this -> arChars;
          }
       
          public function getHash() {
              return $this -> hash;
          }
       
          public function setChars($arr) {
              if (! is_array( $arr ) ) {
                  $arr = preg_split('//u', $arr, -1, PREG_SPLIT_NO_EMPTY);
              }
              if (2 <= count($arr) ) {
                  $test = array_unique($arr);
                  if ( $test == $arr) {
                      $this -> arChars = $arr;
                      $this -> hash = $this -> mkHash($arr);
                      return count($arr);
                  } else {
                      trigger_error ( 'class: numberSystem, function: setChars :: Der übergebene Array ist nicht unique', E_USER_ERROR );
                  }
              } else {
                  trigger_error ( 'class: numberSystem, function: setChars :: Es wurde kein Array übergeben oder der Array hat weniger als zwei Elemente', E_USER_ERROR );
              }
              return false;
          }
       
          private function mkHash( $arr ) {
              $i=0;
              foreach ( $arr as $element ) {
                  $hash[$element] = $i++;
              }
              return $hash;
          }
       
          public function getDec( $str ) {
              $number = 0;
              $length = strlen($str);
              for ( $i = $length; $i > 0; $i-- ) {
                  $inv  = $length - ( $i );
                  $char = $str[( $i-1 )];
                  if ( ! isset ( $this -> hash[$char] ) ) {
                      trigger_error ( 'class: numberSystem, function: getNumberFromString :: Das Zeichen "'.$char.'" ist in der verwendeten Symboltabelle nicht enthalten', E_USER_ERROR );
                      return false;
                  }
                  $number = $number +  pow( count($this -> hash), $inv ) * ( $this -> hash[$char] );
              }
              return $number;
          }
       
          function getString( $int ) {
              # gibt die Zahl aus dem beliebigen Zahlensystem (String)  zurück
             if ( $int > PHP_INT_MAX ) {
                  trigger_error ( 'class: numberSystem, function: getString :: Es wurde eine zu große Zahl ('.$int.') übergeben. Maximum ist '. PHP_INT_MAX , E_USER_ERROR );
              }
              if ( 0 == $int ) {
                  return $this -> arChars[$int];
              }
              $length    = count($this -> arChars);
              $str       = '';
              $positions = 0;
              while ( pow( $length, $positions ) <= $int ) {
                      $positions++;
              }
              for ($i = $positions; $i > 0; $i-- ) {
                      $potenz = pow( $length, $i-1 );
                      $pos = floor( $int / $potenz );
                      $int = $int % $potenz;
                      $str = $str . $this -> arChars[$pos];
              }
              return $str;
          }
      }
      
      

      ... läuft noch mit PHP 8.0 😀-)

    2. Hallo Rolf,

      TIL: PHP kann Strings inkrementieren 😲.

      ich wusste das auch noch nicht, und halte dieses "Feature" für höchst fragwürdig.

      $a = "123_Z";
      $b = "123Z";
      $c = "Z";
      
      ++$a;
      ++$b;
      ++$c;
      
      echo "$a \n";    // 123_A
      echo "$b \n";    // 124A
      echo "$c \n";    // AA
      

      Die Logik dahinter erschließt sich mir nicht. Versucht PHP tatsächlich, die semantische Bedeutung eines Strings zu erraten und das basierend auf dieser Semantik zu incrementieren?
      Aber selbst wenn, dann geht das erste Beispiel doch komplett in die Binsen. Nach welcher Logik ist "123_A" der Nachfolger von "123_Z"?

      Und was ist hiermit:

      $s = "March";
      $s++;
      echo $s;
      

      Wird hier etwa "April" ausgegeben? Wäre ja irgendwie logisch.
      Ich habe auf die Schnelle kein PHP zur Hand, sonst würde ich es ausprobieren.

      Man kann für jede einzelne der gezeigten Verhaltenweisen gute Gründe finden

      Echt? Versuch's mal. Vor allem für den ersten Fall bin ich ratlos.

      Live long and pros healthy,
       Martin

      --
      Früher war ich klein und dumm. Inzwischen hat sich so manches geändert. Ich bin größer geworden.
      1. Hallo,

        Und was ist hiermit:

        $s = "March";
        $s++;
        echo $s;
        

        Wird hier etwa "April" ausgegeben? Wäre ja irgendwie logisch.
        Ich habe auf die Schnelle kein PHP zur Hand, sonst würde ich es ausprobieren.

        Mein PHP antwortet mit "Marci"...

        Gruß
        Kalk

        1. Hi,

          Und was ist hiermit:

          $s = "March";
          $s++;
          echo $s;
          

          Wird hier etwa "April" ausgegeben? Wäre ja irgendwie logisch.
          Ich habe auf die Schnelle kein PHP zur Hand, sonst würde ich es ausprobieren.

          Mein PHP antwortet mit "Marci"...

          okay, das ist, was ich ohne diese ganze Magie erwartet hätte: Der Code des letzten Zeichens im String wird incrementiert, bei einem Überlauf dann auch das vorletzte, und so weiter.

          Trotzdem: Ich halte den Increment- oder Decrement-Operator im Zusammenhang mit Strings für "Mumpity"++.

          Live long and pros healthy,
           Martin

          --
          Früher war ich klein und dumm. Inzwischen hat sich so manches geändert. Ich bin größer geworden.
          1. Hallo,

            "Mumpity"++.

            wenn nicht sogar "Mumpitx"+++

            Gruß
            Kalk

          2. Hallo Martin,

            Ich halte den Increment- oder Decrement-Operator im Zusammenhang mit Strings für "Mumpity"++.

            MMD 😂

            Decrement ist für gemischte Strings übrigens nicht definiert.

            "Z99" kann man nicht dekrementieren. "99" dagegen schon. Argh!

            Rolf

            --
            sumpsi - posui - obstruxi
            1. n'Abend,

              Ich halte den Increment- oder Decrement-Operator im Zusammenhang mit Strings für "Mumpity"++.

              MMD 😂

              graag gedaan. 😀

              Decrement ist für gemischte Strings übrigens nicht definiert.

              "Z99" kann man nicht dekrementieren. "99" dagegen schon. Argh!

              Wunderbar logisch und konsequent. PHP ist echt immer für Überraschungen gut!
              Ich liebe es wie Apfelmus, von dem ich leider kotzen muss[1].

              Live long and pros healthy,
               Martin

              --
              Früher war ich klein und dumm. Inzwischen hat sich so manches geändert. Ich bin größer geworden.

              1. Nein, nicht wirklich. Aber der Spruch passt gerade so gut hierher. ↩︎

            2. Hallo Rolf B,

              MMD 😂

              inc(MMD) = MMDI.

              Bis demnächst
              Matthias

              --
              Du kannst das Projekt SELFHTML unterstützen,
              indem du bei Amazon-Einkäufen Amazon smile (Was ist das?) nutzt.
              1. Hallo,

                MMD 😂

                inc(MMD) = MMDI.

                2501? Kann PHP jetzt auch römisch zählen?

                Gruß
                Kalk

                1. Hallo Tabellenkalk,

                  MMD 😂

                  inc(MMD) = MMDI.

                  2501? Kann PHP jetzt auch römisch zählen?

                  Ja. Keine Ahnung. Ich kann.

                  Bis demnächst
                  Matthias

                  --
                  Du kannst das Projekt SELFHTML unterstützen,
                  indem du bei Amazon-Einkäufen Amazon smile (Was ist das?) nutzt.
              2. Hallo Matthias,

                $a = "MMD";
                $a++;
                echo $a;
                
                MME
                

                leider nicht. Das war wohl selbst R.L. zu viel der Obskurität ⚔️

                Rolf

                --
                sumpsi - posui - obstruxi
          3. Hallo Der Martin,

            Trotzdem: Ich halte den Increment- oder Decrement-Operator im Zusammenhang mit Strings für "Mumpity"++.

            Müsste es nicht ++"Mumpity" heißen?

            Bis demnächst
            Matthias

            --
            Du kannst das Projekt SELFHTML unterstützen,
            indem du bei Amazon-Einkäufen Amazon smile (Was ist das?) nutzt.
            1. Hallo Matthias,

              Müsste es nicht ++"Mumpity" heißen?

              Auf keinen Fall. Es muss

               $unsinn = "Mumpity"; 
               ++$unsinn;
              

              heißen, weil man Literale nicht inkrementieren kann 😉

              Ob das ++ davor oder dahinter kommen muss, oder ob das überhaupt relevant ist, hängt vom Kontext ab. Weißt Du aber sicherlich.

              Rolf

              --
              sumpsi - posui - obstruxi
            2. n'Abend Matthias,

              Trotzdem: Ich halte den Increment- oder Decrement-Operator im Zusammenhang mit Strings für "Mumpity"++.

              Müsste es nicht ++"Mumpity" heißen?

              das ist egal, solange der Ausdruck nicht selbst Teil eines übergeordneten Ausdrucks ist. Denn ++$x bedeutet: Erhöhe $x um eins, schreibe den Wert zurück und liefere den so erhaltenen Wert als Ergebnis (Pro-Increment), während $x++ bedeutet: Merk dir den Wert von $x als Ergebnis vor, erhöhe ihn um 1 und schreibe ihn zurück (Post-Increment).

              Aber Rolf hat natürlich auch Recht: Der Increment- oder Decrement-Operator braucht als Operanden ein LValue, also einen Ausdruck, der links von einem Zuweisungszeichen stehen kann. Oder anders gesagt: Ein Ausdruck, der einen Speicherplatz repräsentiert.

              Live long and pros healthy,
               Martin

              --
              Früher war ich klein und dumm. Inzwischen hat sich so manches geändert. Ich bin größer geworden.
      2. Hallo Martin,

        ja, Marci. Ist doch logisch ;)

        Ich identifiziere folgende Regeln (und übersehe vermutlich Ausnahmen):

        1. Sei $string die zu inkrementierende Zeichenkette.
        2. Setze $p auf LEN($string)-1.
        3. Ist $p == -1, beende die Operation mit "1" als Ergebnis.
        4. Setze $c auf $string[$p]
        5. Ist $c ein Match für /[0-8A-Ya-y]/, inkrementiere seinen Zeichencode um 1, schreibe $c nach $string[$p] und beende die Operation mit $string als Ergebnis.
        6. Ist $c == "9", setze $c auf "0"
        7. Ist $c == "Z", setze $c auf "A"
        8. Ist $c == "z", setze $c auf "a"
        9. Schreibe $c nach $string[$p]
        10. Setze $p auf $p - 1. Solange $p nicht negativ ist, setze bei 4. fort.
        11. Ist $c == "a" oder $c == "A", setze $string auf $c . $string. Andernfalls setze $string auf "1" . $string.
        12. Beende die Operation.

        Testfragen: Nenne die Nachfolger von "19Z", "1Z99", "zzz", "zzZ" und "Zzz".

        Rolf

        --
        sumpsi - posui - obstruxi
        1. Hallo Rolf,

          da frage ich mich schon: „Was haben die geraucht?“

          Gruß
          Jürgen

          1. Hi,

            da frage ich mich schon: „Was haben die geraucht?“

            Methamphpetamin.

            cu,
            Andreas a/k/a MudGuard

          2. Hallo Jürgen,

            da frage ich mich schon: „Was haben die geraucht?“

            spannende Frage. Ich glaube, das möchte ich auch mal probieren. 😀
            Wer weiß, was ich dann für hirnrissig-geniale Ideen habe.

            Live long and pros healthy,
             Martin

            --
            Früher war ich klein und dumm. Inzwischen hat sich so manches geändert. Ich bin größer geworden.