Gogo: UTF-8 String mit strtr() filtern

Guten Tag!

kann mir bei folgenden Script etwas anbrennen?

  
<?php  
  $special_character = Array  
  (  
    '"' => '&quot;',  
    '<' => '&lt;',  
    '>' => '&gt;',  
    '&' => '&amp;'  
  );  
  $string_row = '### Hiroshima <広島市> ###';  
  $string_cooked = strtr($string_row, $special_character);  
  echo $string_cooked;  
?>  

Ich frage deshalb, weil ich für $string_row keinen Zeichensatz angegeben habe. Und da ein UTF-8 Zeichen mehr als ein Byte hat, könnte doch im Bytestream bei einen langen Zeichen zufällig ein '"' etc. vorkommen.

Danke für eine Antwort, Gogo

  1. Hi,

    kann mir bei folgenden Script etwas anbrennen?

    Es *ist* bereits.

    <?php
      $special_character = Array
      (
        '"' => '&quot;',
        '<' => '&lt;',
        '>' => '&gt;',
        '&' => '&amp;'
      );
      $string_row = '### Hiroshima <広島市> ###';
      $string_cooked = strtr($string_row, $special_character);
      echo $string_cooked;
    ?>

      
    Sich das, was [htmlspecialchars](http://www.php.net/manual/en/function.htmlspecialchars.php) bereits hervorragend und auch unter Berücksichtigung der Zeichenkodierung leistet, auf derart umständliche Weise nach zu basteln, ist ziemlich „hirnverbrannt“.  
      
    MfG ChrisB  
      
    
    -- 
    RGB is totally confusing - I mean, at least #C0FFEE should be brown, right?
    
    1. Sich das, was htmlspecialchars bereits hervorragend und auch unter Berücksichtigung der Zeichenkodierung leistet, auf derart umständliche Weise nach zu basteln, ist ziemlich „hirnverbrannt“.

      Ja, es ist nachgebastelt - aber es geht um eine eigene Suche-Ersetzt-Liste. Ich habe das Beispiel mit Absicht so gewählt, daß es für jedermann verständlich ist ... Die Frage ist ganz konkret wie man den Zeichensatz des unbearbeiteten Strings definieren kann.

      Gogo

      1. Hi,

        Ja, es ist nachgebastelt - aber es geht um eine eigene Suche-Ersetzt-Liste. Ich habe das Beispiel mit Absicht so gewählt, daß es für jedermann verständlich ist ...

        Wenn dein Beispiel nicht deutlich macht, was du eigentlich vorhast, sondern stattdessen eher suggeriert, dass du Blödsinn vorhast, ist das nicht besonders hilfreich.

        Die Frage ist ganz konkret wie man den Zeichensatz des unbearbeiteten Strings definieren kann.

        Gar nicht.
        Wozu sollte man?

        Liefere die Parameter für die zu ersetzenden Zeichen/Strings in der gleichen Kodierung wie dein String in dem du sie ersetzen lassen willst.
        Welches Problem soll es denn dann noch geben?

        MfG ChrisB

        --
        RGB is totally confusing - I mean, at least #C0FFEE should be brown, right?
        1. Liefere die Parameter für die zu ersetzenden Zeichen/Strings in der gleichen Kodierung wie dein String in dem du sie ersetzen lassen willst.
          Welches Problem soll es denn dann noch geben?

          Das Zeichen "<" z.B. hat sowohl in ASCII wie auch in UTF-8 den Wert 3c hex. Das Byte 3c hex kann aber in einem UTF-8 String sowohl das Zeichen "<" wie auch Teil eines längern Zeichens sein. In UTF-8 ist ein Zeichen ja nicht auf ein Byte beschränkt.

          Ich klebe auch nicht an der Funktion strtr(). Ich suche nach einer Möglichkeit UTF-8 Strings sauber zu filtern.

          Gogo

          1. Hi,

            Das Zeichen "<" z.B. hat sowohl in ASCII wie auch in UTF-8 den Wert 3c hex. Das Byte 3c hex kann aber in einem UTF-8 String sowohl das Zeichen "<" wie auch Teil eines längern Zeichens sein.

            Eine „Verwechslungsgefahr“ besteht da trotzdem nicht.

            Beschäftige dich mal damit, wie UTF-8 funktioniert: http://de.wikipedia.org/wiki/UTF-8#Kodierung

            MfG ChrisB

            --
            RGB is totally confusing - I mean, at least #C0FFEE should be brown, right?
          2. Hi!

            Das Zeichen "<" z.B. hat sowohl in ASCII wie auch in UTF-8 den Wert 3c hex. Das Byte 3c hex kann aber in einem UTF-8 String sowohl das Zeichen "<" wie auch Teil eines längern Zeichens sein. In UTF-8 ist ein Zeichen ja nicht auf ein Byte beschränkt.

            Schau dir bitte die Bildungsvorschrift von UTF-8 an.

            Ich klebe auch nicht an der Funktion strtr(). Ich suche nach einer Möglichkeit UTF-8 Strings sauber zu filtern.

            Definiere filtern, besonders sauber filtern.

            Lo!

        2. @@ChrisB:

          nuqneH

          Liefere die Parameter für die zu ersetzenden Zeichen/Strings in der gleichen Kodierung wie dein String in dem du sie ersetzen lassen willst.
          Welches Problem soll es denn dann noch geben?

          Ersetze '¼' durch '½' und schon werden alle 'ü' zu 'ý'.

          Qapla'

          --
          Gut sein ist edel. Andere lehren, gut zu sein, ist noch edler. Und einfacher.
          (Mark Twain)
          1. Hi!

            Liefere die Parameter für die zu ersetzenden Zeichen/Strings in der gleichen Kodierung wie dein String in dem du sie ersetzen lassen willst.
            Welches Problem soll es denn dann noch geben?
            Ersetze '¼' durch '½' und schon werden alle 'ü' zu 'ý'.

            Du bist aber heute sehr unaufmerksam. Es geht um "in der gleichen Kodierung", nicht um einen Mischmasch zwischen ISO-8850-1 und UTF-8.

            Lo!

            1. @@dedlfix:

              nuqneH

              Du bist aber heute sehr unaufmerksam.

              Touché!

              Und du? ;-)

              Qapla'

              --
              Gut sein ist edel. Andere lehren, gut zu sein, ist noch edler. Und einfacher.
              (Mark Twain)
      2. Hi!

        Die Frage ist ganz konkret wie man den Zeichensatz des unbearbeiteten Strings definieren kann.

        Gar nicht. PHP arbeitet nicht mit Zeichensätzen und an ganz wenigen Stellen mit konkreten Zeichenkodierungen. Wo das Manual nicht konkretes dazuschreibt, basiert alles auf Bytes.

        Für dein Beispiel im OP: Schau dir an, wie UTF-8 definiert ist, welche Bytewerte verwendet werden, besonders den Unterschied zwischen ASCII- und anderen Zeichen.

        Lo!

  2. @@Gogo:

    nuqneH

    […] keinen Zeichensatz angegeben habe. Und da ein UTF-8 Zeichen […]

    Es gibt keine UTF-8-Zeichen, auch nicht ohne Deppenleerzeichen. Unterscheide Zeichensatz und Zeichencodierung!

    strtr() mag zwar in der PHP-Doku unter Stringfunktionen gelistet sein, aber wohl keine der dort stehenden Funktionen verdient den Namen. Stingfunktionen beginnen mit mb_, so wie mb_strstr().

    Und was ChrisB sagte.

    Qapla'

    --
    Gut sein ist edel. Andere lehren, gut zu sein, ist noch edler. Und einfacher.
    (Mark Twain)
    1. Hi!

      Stingfunktionen beginnen mit mb_, so wie mb_strstr().

      Sting != String und strtr != strstr

      Lo!

      1. @@dedlfix:

        nuqneH

        Sting != String und strtr != strstr

        Was will mir die message in a bottle jetzt sagen?

        Qapla'

        --
        Gut sein ist edel. Andere lehren, gut zu sein, ist noch edler. Und einfacher.
        (Mark Twain)
        1. Hi!

          Sting != String und strtr != strstr
          Was will mir die message in a bottle jetzt sagen?

          Dass es einen Unterschied zwischen strtr() und strstr() gibt. Das sind zwei verschiedene Funktionen, die nicht mal ähnliche Aufgaben erledigen. Außerdem gibt es strtr() nicht in der Multibyte-Ausführung.

          Lo!

          1. @@dedlfix:

            nuqneH

            Sting != String und strtr != strstr
            Was will mir die message in a bottle jetzt sagen?

            Dass […]

            Ähm, das war keine Frage, sondern ein Wortspiel. Du kommst drauf? ;-)

            Qapla'

            --
            Gut sein ist edel. Andere lehren, gut zu sein, ist noch edler. Und einfacher.
            (Mark Twain)
            1. Hi!

              Was will mir die message in a bottle jetzt sagen?
              Ähm, das war keine Frage, sondern ein Wortspiel. Du kommst drauf? ;-)

              Weiß nicht. Du willst hoffentlich nicht sagen, dass meins ein Flaschenpost war.

              Lo!

              1. @@dedlfix:

                nuqneH

                Was will mir die message in a bottle jetzt sagen?
                Ähm, das war keine Frage, sondern ein Wortspiel. Du kommst drauf? ;-)
                Weiß nicht.

                http://www.youtube.com/watch?v=G1GTBWxbkSI

                Qapla'

                --
                Gut sein ist edel. Andere lehren, gut zu sein, ist noch edler. Und einfacher.
                (Mark Twain)
                1. Hi!

                  Was will mir die message in a bottle jetzt sagen?
                  Ähm, das war keine Frage, sondern ein Wortspiel. Du kommst drauf? ;-)
                  Weiß nicht.
                  http://www.youtube.com/watch?v=G1GTBWxbkSI

                  Da höre ich nur "Diese Musik ist in deinem Gedächtnis nicht verfügbar." Da war ich wohl früher unaufmerksam - nicht zu unrecht für meinen Geschmack.

                  Lo!

    2. Hi,

      Stingfunktionen beginnen mit mb_

      Die hätten gar nicht in den globalen Namensraum gehört, sondern gefälligst als Methoden einer Klasse Bee oder Wasp angelegt ... zusammengefrickelter Haufen Schund, dieses PHP.

      MfG ChrisB

      --
      RGB is totally confusing - I mean, at least #C0FFEE should be brown, right?
    3. strtr() mag zwar in der PHP-Doku unter Stringfunktionen gelistet sein, aber wohl keine der dort stehenden Funktionen verdient den Namen. Stingfunktionen beginnen mit mb_, so wie mb_strstr().

      Danke! Das sieht gut aus. Stringfunktionen die mit mb_ anfangen scheinen das zu tun was ich suche!

      Gogo

  3. kann mir bei folgenden Script etwas anbrennen?

    Ja. Unterscheide beim Programmieren konsequent zwischen Byte- und Character Semantics. Stelle in jeder Codezeile sicher, ob ein String Bytes oder Zeichen beinhaltet und vermische dies nicht. Operiere entweder mit Bytes ODER mit Zeichenketten. Vergleiche nicht Byte-Sequenzen mit Zeichenketten. Ersetze keine Bytes in Zeichenketten sondern ersetze Zeichen in Zeichenketten. Ersetze keine Zeichen in Bytesequenzen sondern ersetze Bytes in Bytesequenzen. Stelle in der Ausgabe sicher, ob Bytes oder ob Zeichen ausgegeben werden sollen.

    Schönes Wochenende,
    Horst

    1. Hi!

      Unterscheide beim Programmieren konsequent zwischen Byte- und Character Semantics.

      Wenn man zwischen Byte und Zeichen unterscheidet, dann wohl eher, weil das eine Binärdaten sind und das andere Zeichenketten. Wie die Zeichenkette in Bytes abgelegt ist, interessiert in der Regel auch nicht. Und nun müsste man vom allgemeinen Blabla auf die Besonderheiten PHPs eingehen und dabei irgendwelches Perl-Wissen außen vor lassen.

      Für Ein-Byte-Kodierungen ist es völlig belanglos, ob man zeichen- oder bytebasiert Stringoperationen ausführt. Für Mehrbyte-Kodierungen kann man die Bytes unbetrachtet lassen, weil man die Komplexität der Stringverarbeitung lieber passenden Funktionen überlässt, deren Innenleben dabei wenig interessant ist.

      Stelle in jeder Codezeile sicher, ob ein String Bytes oder Zeichen beinhaltet und vermische dies nicht. Operiere entweder mit Bytes ODER mit Zeichenketten. Vergleiche nicht Byte-Sequenzen mit Zeichenketten. Ersetze keine Bytes in Zeichenketten sondern ersetze Zeichen in Zeichenketten. Ersetze keine Zeichen in Bytesequenzen sondern ersetze Bytes in Bytesequenzen. Stelle in der Ausgabe sicher, ob Bytes oder ob Zeichen ausgegeben werden sollen.

      Und ganz wichtig: Verwende keine Äpfel, wenn du Birnenkompot machen willst.

      Lo!

      1. hi,

        ... Für Mehrbyte-Kodierungen kann man die Bytes unbetrachtet lassen, weil man die Komplexität der Stringverarbeitung lieber passenden Funktionen überlässt, deren Innenleben dabei wenig interessant ist.

        Ok, wir testen das mal, 'äöü' sei ein UTF-8-kodierter String (Zeichenkette mit drei Zeichen).

        echo strlen('äöü');

        gibt mir eine 6 als Ergebnis, welche Funktion würde mir denn die Anzahl der Zeichen liefern?

        Hotti

        1. Hi!

          ... Für Mehrbyte-Kodierungen kann man die Bytes unbetrachtet lassen, weil man die Komplexität der Stringverarbeitung lieber passenden Funktionen überlässt, deren Innenleben dabei wenig interessant ist.
          Ok, wir testen das mal, 'äöü' sei ein UTF-8-kodierter String (Zeichenkette mit drei Zeichen).
          echo strlen('äöü');
          gibt mir eine 6 als Ergebnis, welche Funktion würde mir denn die Anzahl der Zeichen liefern?

          Eine passende, wie ich schrieb. PHP ist generell (noch) nicht dafür ausgelegt, Mehrbyte-Kodierungen zu verarbeiten. Mehrbyte-Kodierungen können derzeit nur mit der Multibyte-String-Extension bearbeitet werden und einigen ausgewählten Funktionen, denen üblicherweise explizit die von ISO-8859-1 abweichende Kodierung mitgeteilt werden muss. Als PHP-Verwender muss man die Existenz dieser Funktionen und Parameter kennen, wenn man mit Mehrbyte-Kodierungen arbeiten möchte.

          Lo!

          1. hi,

            echo strlen('äöü');
            gibt mir eine 6 als Ergebnis, welche Funktion würde mir denn die Anzahl der Zeichen liefern?

            PHP ist generell (noch) nicht dafür ausgelegt, Mehrbyte-Kodierungen zu verarbeiten.

            Na, das ist doch mal ne Aussage ;-)

            Danke Dir,
            Grüße an Alle,
            Horst

            PS:

            Theoretisch könnte ich jetzt ne Runde schlafen. Praktisch wäre es Zeitverschwendung.

          2. Moin!

            PHP ist generell (noch) nicht dafür ausgelegt, Mehrbyte-Kodierungen zu verarbeiten. Mehrbyte-Kodierungen können derzeit nur mit der Multibyte-String-Extension bearbeitet werden und einigen ausgewählten Funktionen, denen üblicherweise explizit die von ISO-8859-1 abweichende Kodierung mitgeteilt werden muss.

            Also würde ich dir doch mal spontan widersprechen: PHP _IST_ dafür ausgelegt, Mehrbyte-Kodierungen zu verarbeiten. Denn die mb-Extension macht ja genau das.

            Allerdings erlaubt es PHP derzeit nicht, Mehrbyte-Kodierungen TRANSPARENT mit den regulären Stringfunktionen zu bearbeiten (außer man aktiviert das Overloading - halte ich aber eher für ungeeignet).

            Unter dem Strich ist man mit PHP dadurch eigentlich in einer gemischten Lage: Auf der einen Seite ist man in der Lage, je nach Wunsch sowohl auf Basis von Bytes oder von Zeichen zu arbeiten, indem man eben mb_*-Funktionen oder normale "String"-Funktionen verwendet. Auf der anderen Seite muss man sich eben genau dieser Unterscheidung immer bewußt sein, und es gibt halt nicht für jede String-Funktion eine identische mb-Funktion.

            Insgesamt darf man den Zustand der Codierungsmöglichkeiten in PHP durchaus als chaotisch bezeichnen, weil sich die diversen Extensions bzw. Funktionsgruppen hinsichtlich der Kodierung ihr eigenes Süppchen gekocht haben im Laufe der Zeit. Einige arbeiten im ASCII-/ISO-8859-1-Raum, einige arbeiten mit UTF-8-Kodierung, einige erlauben einen Kodierungsparameter.

            Auf der anderen Seite ist festzustellen, dass PHP mit UTF-8 sehr gut umgehen kann, wenn man gewisse Dinge beachtet. Und weil diese Dinge immer gleichartig zu beachten sind, lernt man im Laufe der Zeit, sie automatisch korrekt anzuwenden - ungefähr so, wie die Anwendung der korrekten Prüfung mit strpos() auf Abwesenheit des gesuchten Strings vs. Fundstelle an Position 0 im String.

            Als PHP-Verwender muss man die Existenz dieser Funktionen und Parameter kennen, wenn man mit Mehrbyte-Kodierungen arbeiten möchte.

            Eben. Und PHP wird im Zweifel den String einfach fehlkodiert weiterreichen und das Problem dann dem Programmierer oder dem Anwender aufhalsen.

            Ich kenne ein Negativ-Beispiel aus Python. Der Spamfilter für Trac ist offensichtlich von einem Programmierer aus der ASCII-Welt geschrieben worden. Wenn ein User Texte mit Umlauten postet, dann steigt der Spamfilter mit einem Kodierungsfehler aus, und der Spam-Score ist 0. Mit ASCII-Zeichen allein funktioniert es. Dieses eigenmächtige Fehlerwerfen von Python, welches nur im UTF-8-Fall auftritt (über die Problematik, die Kodierung eines Textes immanent zu erkennen, brauchen wir nicht diskutieren), halte ich für deutlich problematischer, als das in PHP anzunehmende Verhalten, an dieser Stelle einfach den Spam-Text mit "merkwürdigen Zeichen" zu durchforsten und eben gerade NICHT auszusteigen.

            Mit anderen Worten: Kodierungsprobleme kann man sich in JEDER Sprache einhandeln, wenn man die Regeln nicht kennt und nicht darauf achtet. Jede Applikation hat dafür zu sorgen, dass sie die hereinkommenden Zeichenketten mit der verwendeten Kodierung taggt und (noch nicht bei PHP) im Bedarfsfall on-the-fly umkodiert, wenn die Ausgabe eine andere Kodierung verlangt. Dies geschieht entweder durch eine entsprechende Angabe der Datenquelle selbst (HTTP-Header, Meta-Tags in HTML), bei Fehlen derselben muss die Kodierung halt explizit im Programm definiert werden. Ohne solch eine Angabe sollte im Prinzip jede Software sofort anhalten und die fehlende Kodierungsdefinition bemängeln.

            Aber wir wünschen uns ja auch schon seit zwanzig Jahren Browser, die bei fehlerhaftem, invalidem HTML aussteigen und den Fehler monieren...

            - Sven Rautenberg

            1. Hi!

              PHP ist generell (noch) nicht dafür ausgelegt, Mehrbyte-Kodierungen zu verarbeiten. Mehrbyte-Kodierungen können derzeit nur mit der Multibyte-String-Extension bearbeitet werden und einigen ausgewählten Funktionen, denen üblicherweise explizit die von ISO-8859-1 abweichende Kodierung mitgeteilt werden muss.
              Also würde ich dir doch mal spontan widersprechen: PHP _IST_ dafür ausgelegt, Mehrbyte-Kodierungen zu verarbeiten. Denn die mb-Extension macht ja genau das.

              Ja, sie fügen Funktionalität hinzu, deswegen ist es aber immer noch nicht für Mehrbyte-Funktionalität ausgelegt. Diese Erweiterung ist auch optional und standardmäßig nicht aktiviert. Damit PHP generell mehrbytefähig wird, muss intern ein grundlegender Umbau stattfinden, was erst zur nächsten Major-Version geplant ist, bei der man sich einge gewisse Menge Inkompatibilität zur Vergangenheit leisten kann.

              Vielleicht hätte ich besser das Wort "generell" nach dem "nicht" eingeordnet.

              Lo!

            2. @@Sven Rautenberg:

              nuqneH

              Aber wir wünschen uns ja auch schon seit zwanzig Jahren Browser, die bei fehlerhaftem, invalidem HTML aussteigen und den Fehler monieren...

              Liefere XHTML als XML aus, dann sollte genau das passieren. Ist das wirklich wünschenswert?

              Qapla'

              --
              Gut sein ist edel. Andere lehren, gut zu sein, ist noch edler. Und einfacher.
              (Mark Twain)
      2. hi,

        Wenn man zwischen Byte und Zeichen unterscheidet, dann wohl eher, weil das eine Binärdaten sind und das andere Zeichenketten. Wie die Zeichenkette in Bytes abgelegt ist, interessiert in der Regel auch nicht. Und nun müsste man vom allgemeinen Blabla auf die Besonderheiten PHPs eingehen und dabei irgendwelches Perl-Wissen außen vor lassen.

        Ein Programmmierer wird sich sehr wohl dafür interessieren müssen, sonst fällt er nuhr auf die Fresse.

        Guck Dir ruhig mal an, wie in Perl zwischen Bytesemantics und Charactersemantics unterschieden wird (Btw. seit v5.6.1, 2002), es wird auch in PHP so kommen.

        Danke fürs Verständnis,
        Schönen Sonntag!

        1. Hi!

          Ein Programmmierer wird sich sehr wohl dafür interessieren müssen, sonst fällt er nuhr auf die Fresse.
          Guck Dir ruhig mal an, wie in Perl zwischen Bytesemantics und Charactersemantics unterschieden wird (Btw. seit v5.6.1, 2002), es wird auch in PHP so kommen.

          Das kann durchaus sein, aber das nützt nur im Moment nichts. Vielleicht halten irgendwann später irgendwelche aus anderen Systemen bekannte Paradigmen in PHP Einzug, aber auch diese sind derzeit nicht relevant.

          Lo!

        2. Hi,

          Guck Dir ruhig mal an, wie in Perl zwischen Bytesemantics und Charactersemantics unterschieden wird

          Wenn mich dieses Thema interessiert, dann lese ich darüber lieber in offiziellen Quellen nach ...

          MfG ChrisB

          --
          RGB is totally confusing - I mean, at least #C0FFEE should be brown, right?