multibyte-Vergleiche

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • multibyte-Vergleiche

    Hallo

    In Java ist es bei ASCII-Zeichen erlaubt, die Zeichen mittels z. B. < oder > zu vergleichen, weil im Hintergrund die ASCII-Zeichen verglichen werden. Doch wie schaut das in PHP und UTF-8 aus?

    Ich habe schon etwas herumexperimentiert ... und wurde überrascht.

    PHP-Code:
    <?php
       error_reporting
    (-1);
       
       
    mb_internal_encoding('UTF-8');
       
       
    var_dump('I' 'Y');  // 49 < 59 => true OK
       
    var_dump('IZ' 'Y'); // 49, 5a < 59 => true OK
       
    var_dump('§' 'µ');  // c2a7 < c2b5 => true OK
       
    var_dump('§' 'µ');  // c2a7 > c2b5 => false OK
    ?>
    Interessanterweise kommt überall die richtige Ausgabe, so wie ich es erhofft hatte.

    Allerdings hätte ich eigentlich vermutet, dass das gar nicht geht, dass man so gar keine UTF-8-Zeichen vergleichen darf. Ich hätte eigentlich vermutet, dass nur byteweise verglichen wird (immer nur das erste Byte der beiden Zeichen). Dann hätte der dritte var_dump false ausgeben müssen, da die ersten Bytes der beiden Zeichen § und µ gleich sind.

    Also darf man das offiziell so machen? Darf man in PHP UTF-8-Zeichen mit < und > vergleichen?

    Backgroundinfo: es interessiert mich wegen dem hier: http://www.unistreams.de/vorlesungen...4-kapitel-3-1/ ab Minute 53 (ich kann übrigens alle Vorlesungen dieses Profs empfehlen, der ist gut )
    Zuletzt geändert von narutos; 04.10.2014, 19:20.
    Aufgrund Spams ignoriere ich h3ll.

  • #2
    PHP kann kein UTF-8. Strings werden wie Byte-Arrays behandelt.

    Kommentar


    • #3
      Ok, also nachdem das jetzt schon das zweite Thema ist, in dem du spamst und du auch nicht aufhörst, obwohl ich dich schon gebeten habe, muss ich das jetzt melden. PHP kann sehr wohl UTF-8, das beweist schon alleine der mb_internal_encoding-Funktionsaufruf.
      Zuletzt geändert von narutos; 04.10.2014, 20:32.
      Aufgrund Spams ignoriere ich h3ll.

      Kommentar


      • #4
        Ist jetzt vielleicht etwas off-topic, aber du könntest vielleicht mal diese beiden Leute irgendwie kontaktieren:

        - veryhot (php.de)
        - kudlimudli (phpforum.de, hat glaube ich auch noch andere Accounts)

        (Müsstest dir dazu dort vermutlich jeweils einen Account erstellen.)

        Die beschäftigen sich mit sehr ähnlichen Themen wie du (etwa Vornberger-Vorlesungen). Vielleicht könnt ihr euch untereinander austauschen und dann auch Rechercheaufgaben unter euch aufteilen oder dergleichen. Ich denke, das wäre für euch alle ganz fruchtbar.

        Nur eine wilde Idee.

        Kommentar


        • #5
          Also ich finde, irgendwie macht das der Prof etwas umständlich. Zuerst prüft er in der Schleife, danach nochmals nach der Schleife. Spricht was dagegen, die Kontrollen ausschließlich nur in der Schleife durchzuführen?
          PHP-Code:
          <?php
             error_reporting
          (-1);
             
             
          mb_internal_encoding('UTF-8');
             
             
          /*var_dump('I' < 'Y');  // 49 < 59 => true OK
             var_dump('IZ' < 'Y'); // 49, 5a < 59 => true OK
             var_dump('§' < 'µ');  // c2a7 < c2b5 => true OK
             var_dump('§' > 'µ');  // c2a7 > c2b5 => false OK
             */
             
             
          class MbString
             
          {
                private 
          $text;
                
                function 
          __construct($text)
                {
                   
          $this->text $text;
                }
                function 
          cmp(MbString $other)
                {
                   
          $thisLen mb_strlen($this->text);
                   
          $otherLen mb_strlen($other->text);
                   for(
          $i 0; ; ++$i)
                   {
                      if(
          $i >= $thisLen)
                         return 
          $i >= $otherLen : -$i;
                      if(
          $i >= $otherLen)
                         return 
          $i;
                      if(
          mb_substr($this->text$i1) != mb_substr($other->text$i1))
                         return 
          mb_substr($this->text$i1) < mb_substr($other->text$i1) ? -$i $i;
                   }
                }
             }
             
             
          $otherS = new MbString('ab');
             
             
          $thisS = new MbString('a');
             
          var_dump($thisS->cmp($otherS)); // this < other => -1
             
             
          $thisS = new MbString('abc');
             
          var_dump($thisS->cmp($otherS)); // this > other => 2
             
             
          $thisS = new MbString('ab');
             
          var_dump($thisS->cmp($otherS)); // this = other => 0
             
             
          $thisS = new MbString('aa');
             
          var_dump($thisS->cmp($otherS)); // this < other => -1
             
             
          $thisS = new MbString('ax');
             
          var_dump($thisS->cmp($otherS)); // this > other => 1
          ?>
          Ich gehe hier einfach mal davon aus, dass es in PHP offiziell erlaubt ist, dass man Multibyte-Zeichen per < und > vergleichen darf.

          Soviel ich weiß, macht der Vornberger mehrere unterschiedliche Vorlesungen. Und es gibt auch mehrere Professoren, die so ähnliche Vorlesungen halten. Das wäre schon ein Zufall, wenn ich vom gleichen Prof die gleiche Vorlesung erwischt hätte. Das Problem ist ja auch, dass jeder Prof ganz anders unterrichtet. Der Vornberger hat das Thema Floatingpoint-Kodierung z. B. nur sehr rudimentär angesprochen - erwähnt er auch selbst im Vortrag. Andere Profs erklären z. B. auch die unterschiedlichen Rundungsalgorithmen. Und auch die Beispiele sind sicher bei allen Profs ganz unterschiedlich.

          Wie schaut meine Vergleichsvariante aus ?
          Zuletzt geändert von narutos; 04.10.2014, 20:57.
          Aufgrund Spams ignoriere ich h3ll.

          Kommentar


          • #6
            Zitat von narutos Beitrag anzeigen
            Ok, also nachdem das jetzt schon das zweite Thema ist, in dem du spamst und du auch nicht aufhörst, obwohl ich dich schon gebeten habe, muss ich das jetzt melden. PHP kann sehr wohl UTF-8, das beweist schon alleine der mb_internal_encoding-Funktionsaufruf.
            Ich weiß nicht, welches Problem du hast. Fakt ist, dass PHP keine Multi-Byte-Strings unterstützt und dass über dessen Einführung schon jahrelang Debatten geführt werden - ohne Ergebnis.

            Auch die genannten mb_* Funktionen sind nur Workarounds, die mit Byte-Arrays arbeiten.

            Zitat von narutos Beitrag anzeigen
            Wie schaut meine Vergleichsvariante aus?
            Schlecht, da du nur Bytes und keine Multi-Byte-Strings vergleichst.

            Mal davon abgesehen, dass der Code generell nicht funktioniert, weil cmp() in dem Fall immer 0 liefert:

            PHP-Code:
            $values array_merge(range(09), range('A''Z'), range('a''z'), ['Ä''Ö''Ü''ä''ö''ü''ß']);

            usort($values, function ($a$b) {
                return (new 
            MbString($a))->cmp(new MbString($b));
            });
            echo 
            implode($values);
            // lkjmnpoihcbadegfqrÜÖÄäößüzytsuvxwZYCBADEGF983214576HITSRUVXWQPKJLMON0 
            Zuletzt geändert von h3ll; 04.10.2014, 21:13.

            Kommentar


            • #7
              Zitat von narutos Beitrag anzeigen
              In Java ist es bei ASCII-Zeichen erlaubt, die Zeichen mittels z. B. < oder > zu vergleichen, weil im Hintergrund die ASCII-Zeichen verglichen werden.
              Nein. Java-Strings bestehen aus Unicode-"Zeichen"-Sequenzen (normalerweise intern als UTF-16 kodiert). Die gehen über ASCII weit hinaus. Wie die Java-Vergleichsoperatoren mit solchen Strings umgehen, entzieht sich meiner Kenntnis. Aber höchstwahrscheinlich vergleichen sie nur Codepoints, keine Graphem-Cluster (wie es ein menschlicher Leser tun würde).

              Außerdem dürften sie keine Collation-Sequences kennen, d.h. das Vergleichen nach bestimmten Regeln (bspw. wie in Telefonbüchern oder Wörterbüchern). Die sind nämlich von der Sprache und teilweise sogar vom Land abhängig.

              Java nutzt für diese Zwecke die Funktionen der ICU-Libraries.

              Doch wie schaut das in PHP und UTF-8 aus?
              PHP kann ASCII-Byte-Sequenzen vergleichen. Je nachdem, mit welcher Lokalisierung dein PHP compiliert wurde, kann es auch 8-Bit-Zeichensätze, die über ASCII hinausgehen vergleichen. Das war es auch schon. H3ll hat recht. Deal with it.

              Es gibt allerdings Erweiterungen für PHP, die beschränkt mit anderen Kodierungen umgehen können. Die Multibyte-Extension kann mit vielen verschiedenen Kodierungen außerhalb des ASCII|8-Bit-Bereiches arbeiten. Vergleichsfunktionen oder Collation-Sequences kennt sie aber nicht.

              Die "intl"-Erweiterung basiert auf ICU und nutzt zu einem Großteil die Java-APIs. Das ist gut, weil man so die Java-API-Dokumentation zu Rate ziehen kann. Die PHP-Dokumentationen sind derzeit nahezu unbrauchbar. Außerdem hängt die Funktionalität stark von der PHP-Version ab (es kommt ständig was hinzu).

              "Intl" besitzt eigene Funktionen für String-Vergleiche und zum Erzeugen von Vergleichsschlüsseln falls du dir deine Vergleichsfunktionen selbst basteln möchtest.

              Ich habe schon etwas herumexperimentiert ... und wurde überrascht.

              PHP-Code:
              <?php
                 error_reporting
              (-1);
                 
                 
              mb_internal_encoding('UTF-8');
                 
                 
              var_dump('I' 'Y');  // 49 < 59 => true OK
                 
              var_dump('IZ' 'Y'); // 49, 5a < 59 => true OK
                 
              var_dump('§' 'µ');  // c2a7 < c2b5 => true OK
                 
              var_dump('§' 'µ');  // c2a7 > c2b5 => false OK
              ?>
              Interessanterweise kommt überall die richtige Ausgabe, so wie ich es erhofft hatte.
              Hüh? Klar kommt die "richtige" Ausgabe. UTF-8-Byte-Sequenzen wurden extra so konstruiert, um herkömmliche 8-Bit-String-Vergleichsfunktionen nicht zu verwirren.

              Nebenbei gibt es noch ein weiteres Problem: Die interne Kodierung von PHP-String-Literale in einfachen Hochkommas hängt vom verwendeten Editor ab. Da du nur Zeichen aus dem 8-Bit-Bereich verwendet hast, sagt dein Quelltext gar nichts darüber aus, ob das Zeichen '§' jetzt intern als 0x87 (ISO-Latin-1) oder 0xC2 0xA7 (UTF-8) kodiert wurde. Probiere das mit Codepoints > 0xFF und du wirst vielleicht einige Überraschungen erleben.

              Allerdings hätte ich eigentlich vermutet, dass das gar nicht geht, dass man so gar keine UTF-8-Zeichen vergleichen darf. Ich hätte eigentlich vermutet, dass nur byteweise verglichen wird (immer nur das erste Byte der beiden Zeichen). Dann hätte der dritte var_dump false ausgeben müssen, da die ersten Bytes der beiden Zeichen § und µ gleich sind.
              Nein. Versuche, die interne Arbeitsweise von String-Vergleichsfunktionen zu verstehen, am besten am Quellcode von strcmp()-, memcmp()-Funktionen in C-Quellcode (bpsw. in den PHP-Sources). Dann wirst du sehen, dass deine Vermutung nicht korrekt ist.

              Also darf man das offiziell so machen? Darf man in PHP UTF-8-Zeichen mit < und > vergleichen?
              Ja. PHP-Strings sind nichts anderes als in der Länge veränderbare Byte-Arrays. Genauso werden sie von den (meisten) PHP-Stringfunktionen (der Standard-Library) auch behandelt. Die Vergleichsoperatoren tun das ebenfalls. Ob die Bytes jetzt ASCII, ISO-Latin-1, UTF-8 oder was auch immer darstellen, ist denen wurst. Sie vergleichen Byte für Byte. UTF-8 ist so konstruiert, dass solche dummen Funktionen oder Operatoren trotzdem "funktionieren". Das ist eine Eigenschaft von UTF-8, aber nicht von PHPs String-Funktionen/-Operatoren.

              Backgroundinfo: es interessiert mich wegen dem hier: Unistreams Algorithmen WS 2013/14 - Kapitel 3.1 - Unistreams ab Minute 53 (ich kann übrigens alle Vorlesungen dieses Profs empfehlen, der ist gut )
              Inhalt dieser Vorlesung:

              In der Vorlesungsreihe “Algorithmen” werden anhand der Programmiersprache Java Algorithmen zum Suchen und Sortieren vorgestellt und die dazu benötigten Datenstrukturen wie Keller, Schlange, Liste, Baum und Graph eingeführt. Programme werden auf Eigenschaften wie Korrektheit, Terminierung und Effizienz untersucht.
              Mag sein, dass der Mann in Theoretischer Informatik und auch ein wenig in "Algorithmen und Datenstrukturen" gut ist. Mit Textverarbeitung und Unicode-Problemen hat das aber nicht viel zu tun.
              Klingon function calls do not have “parameters”‒they have “arguments”‒and they always win them!

              Kommentar

              Lädt...
              X