Raucherkrebs: Alle komischen Zeichen finden

Mahlzeit Forum,

wie kann man in einer Datenbank alle Zeichen finden, die nicht im UTF-8 Format kodiert sind. Auf der Webseite erscheinen sie als schwarzer Kasten mit einem Fragezeichen drin. Ebenso in phpmyadmin.
Ich muss die noch per Hand in UTF-8 umwandeln. Aber wie finden?
Die DB hat ein paar tausend Zeilen und etliche Tabellen.

Habe versucht über die Suchkuntion nach diesem schwarzen Kasten %�% zu suchen, aber es wird nicht gefunden.

  1. Habe versucht über die Suchkuntion nach diesem schwarzen Kasten %�% zu suchen, aber es wird nicht gefunden.

    Ueber die Suchfunktion nach %?% zu suchen, bringt nichts. Das Fragezeichen in dem schwarzen Balken wird von Browser zu Browser anders dargestellt. Ausserdem ist das ein festgelegtes Zeichen, was du nicht trennen kannst. Diese Zeichen sind auch nicht in der DB drin. Such mal nach Umlauten, Sonderzeichen oder sowas. Die musst du dann "browser-codiert" ausgeben.

  2. 你好 Raucherkrebs,

    wie kann man in einer Datenbank alle Zeichen finden, die nicht im
    UTF-8 Format kodiert sind. Auf der Webseite erscheinen sie als
    schwarzer Kasten mit einem Fragezeichen drin. Ebenso in phpmyadmin.
    Ich muss die noch per Hand in UTF-8 umwandeln. Aber wie finden?
    Die DB hat ein paar tausend Zeilen und etliche Tabellen.

    Da wird dir nichts anderes uebrig bleiben als alle DB-Eintraege
    auszulesen, zu validieren und ggf. zu melden. Als Validierungsfunktion
    kannst du vielleicht das hier von C nach PHP portieren (keine Angst,
    sieht komplizierter aus als es ist):

    int utf8_to_unicode(const u_char *s,size_t n,u_int32_t *num) {
      u_char c = s[0];

    if(c < 0x80) {
        *num = c;
        return 1;
      }
      else if(c < 0xc2) return EILSEQ;
      else if(c < 0xe0) {
        if(n < 2) return EILSEQ;

    if(!((s[1] ^ 0x80) < 0x40)) return EILSEQ;
        *num = ((u_int32_t)(c & 0x1f) << 6) | (u_int32_t)(s[1] ^ 0x80);
        return 2;
      }
      else if(c < 0xf0) {
        if(n < 3) return EILSEQ;
        if(!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40 && (c >= 0xe1 || s[1] >= 0xa0))) return EILSEQ;

    *num = ((u_int32_t)(c & 0x0f) << 12) | ((u_int32_t)(s[1] ^ 0x80) << 6) | (u_int32_t)(s[2] ^ 0x80);
        return 3;
      }
      else if(c < 0xf8) {
        if(n < 4) return EILSEQ;
        if(!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40 && (s[3] ^ 0x80) < 0x40 && (c >= 0xf1 || s[1] >= 0x90))) return EILSEQ;

    *num = ((u_int32_t)(c & 0x07) << 18) | ((u_int32_t)(s[1] ^ 0x80) << 12) | ((u_int32_t)(s[2] ^ 0x80) << 6) | (u_int32_t)(s[3] ^ 0x80);
        return 4;
      }
      else if(c < 0xfc) {
        if(n < 5) return EILSEQ;
        if(!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40 && (s[3] ^ 0x80) < 0x40 && (s[4] ^ 0x80) < 0x40 && (c >= 0xf9 || s[1] >= 0x88))) return EILSEQ;

    *num = ((u_int32_t)(c & 0x03) << 24) | ((u_int32_t)(s[1] ^ 0x80) << 18) | ((u_int32_t)(s[2] ^ 0x80) << 12) | ((u_int32_t)(s[3] ^ 0x80) << 6) | (u_int32_t)(s[4] ^ 0x80);
        return 5;
      }
      else if(c < 0xfe) {
        if(n < 6) return EILSEQ;
        if(!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40 && (s[3] ^ 0x80) < 0x40 && (s[4] ^ 0x80) < 0x40 && (s[5] ^ 0x80) < 0x40 && (c >= 0xfd || s[1] >= 0x84))) return EILSEQ;

    *num = ((u_int32_t)(c & 0x01) << 30) | ((u_int32_t)(s[1] ^ 0x80) << 24) | ((u_int32_t)(s[2] ^ 0x80) << 18) | ((u_int32_t)(s[3] ^ 0x80) << 12) | ((u_int32_t)(s[4] ^ 0x80) << 6) | (u_int32_t)(s[5] ^ 0x80);
        return 6;
      }
      else return EILSEQ;
    }

    int is_valid_utf8_string(const u_char *str,size_t len) {
      register u_char *ptr = (u_char *)str;
      int x;
      int ret;

    for(;*ptr && len > 0;) {
        if((ret = utf8_to_unicode(ptr,len,&x)) == EILSEQ) {
          return -1;
        }

    ptr += ret;
        len -= ret;
      }

    return 0;
    }

    再见,
     CK

    --
    Fortune: "The Computer made me do it."
    http://wwwtech.de/
  3. wie kann man in einer Datenbank alle Zeichen finden, die nicht im UTF-8 Format kodiert sind.

    Wenn man davon ausgehen kann, dass Du nicht verschiedene Kodierungen innerhalb eines Strings benutzt hast (mit ziemlicher Sicherheit, denn sonst wäre der ganze String unbrauchbar), müsstest Du utf-8-Strings mit folgendem PCRE-Muster erkennen können:

    ^([\x00-\x7f]|[\xc0-\xd5][\x80-\xbf]|[\xc0-\xd5][\x80-\xbf]{2}|[\xc0-\xd5][\x80-\xbf]{3}|[\xc0-\xd5][\x80-\xbf]{4}|[\xc0-\xd5][\x80-\xbf]{5})*$

    utf-8 folgt dem Schema "entweder ein einzelnes Byte 0 bis 7f oder ein Startbyte größer als c0 gefolgt von einem bis fünf Folgebytes zwischen 80 und bf, abhängig vom Startbyte" (alle Werte in Hex).

    Falls die Datenbank irgendwie mit regulären Ausdrücken umgehen kann, sollte das Muster alle utf-8-Strings herausfiltern können und mit einem NOT davor entsprechend alle Nicht-utf-8-Strings. Vielleicht musst Du statt der \xnn-Sequenzen die Zeichen direkt eingeben, dass sollte aber mit chr() oä auch kein Problem sein.

    1. Und gleich verbockt, sorry, so soll's sein:

      ^([\x00-\x7f]|[\xc0-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3}|[\xf8-\xfb][\x80-\xbf]{4}|[\xfc-\xfd][\x80-\xbf]{5})*$

      Die Werte sind unter http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 aufgelistet.

      1. ^([\x00-\x7f]|[\xc0-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3}|[\xf8-\xfb][\x80-\xbf]{4}|[\xfc-\xfd][\x80-\xbf]{5})*$

        Hrm ...
        Es handelt sich um die mysql DB 4.0.22. Hätte vieleicht erwähnt werden sollen. Würde es dir etwas ausmachen mir den QUERY mal hinzuschreiben bitte? Verstehe nämlich nicht wie man das obige umsetzt.

    2. Moin!

      Wenn man davon ausgehen kann, dass Du nicht verschiedene Kodierungen innerhalb eines Strings benutzt hast (mit ziemlicher Sicherheit, denn sonst wäre der ganze String unbrauchbar), müsstest Du utf-8-Strings mit folgendem PCRE-Muster erkennen können:

      Mit dem regulären Ausdruck erkennt man, ob der String gültiges UTF-8 ist, oder nicht. Aber man erkennt nicht, ob nicht zufällig eine andere Codierung (z.B. ISO-8859-1) so dumm angeordnet ist, dass es auch gültiges UTF-8 ist, aber deswegen ein Zeichen codiert wird, was im Endeffekt als Kästchen oder Fragezeichen wieder herauskommt.

      Mit anderen Worten: Damit werden nur die Stellen gefunden, die im Sinne von UTF-8 böse sind, aber nicht die Stellen, die im Sinne von UTF-8 absolut in Ordnung sind, aber aus Textsicht fehlerhaft.

      - Sven Rautenberg

      1. Mit anderen Worten: Damit werden nur die Stellen gefunden, die im Sinne von UTF-8 böse sind, aber nicht die Stellen, die im Sinne von UTF-8 absolut in Ordnung sind, aber aus Textsicht fehlerhaft.

        Das ist theoretisch richtig, aber solche Fehlschläge sind mit keiner automatisierten Methode vollständig zu vermeiden. Außerdem sind sie sehr unwahrscheinlich, denn die ISO-8859-Kodierungen für die lateinische Buchstabenfamilie haben ihre Buchstaben bei 192-255. 192-253 sind UTF-8-Startbytes, denen nur (eine zudem bestimmte Anzahl) Zeichen aus dem Bereich 128 bis 191 folgen dürfen, wo aber nur meist selten genutzte grafische Zeichen liegen, fast keine Buchstaben. Ein Text, den das Muster fälschlicherweise für UTF-8 hält, müsste in etwa so aussehen: "Ä« bla bla ä¼±".
        Bei anderen ISO-8859-Kodierungen kommt man aus verschiedenen Gründen auch nicht auf besonders sinnvollere Kombinationen, andere Kodierungen müsste man sich im Detail anschauen.