Elya: Stringlänge und utf-8-Zeichen

Hallo,

ich versuche, kyrillische utf-8-Zeichenketten nach bestimmten definierten Regeln in lateinische umzusetzen. Dazu schreibe ich die Zeichen zunächst einzeln in ein Array. Da mir str_split() und PHP5 noch nicht zur Verfügung steht, habe ich folgendes gebastelt:

  
for ($i=0;$i<strlen($string);$i+=2){  
$substr = substr($string,$i,2); // ein unicode-Zeichen besetzt 2  
                               //Zeichen - deshalb in Zweierschritten  
array_push($kyr_string,$substr);  
    }  

Das entstandene Array wird mit Hilfe einer Library (auch Arrays, Regeln und Ausnahmen) in andere Zeichen umgesetzt. Der Haken ist der Zweierschritt in dem substr-Ausdruck oben. Sind nämlich z.B. einfache lateinische Zeichen im String enthalten, für die strlen($zeichen) == 1 gilt, zerhackt die obige Schleife die weiteren Zeichen (bzw packt sie auch in Zweierpäckchen), so daß die Umsetzung später an dieser Stelle abbricht.

Einigermaßen verständlich?

Ich habe versucht, utf8_encode() auf die Zeichenkette anzuwenden, aber das hat keinen Effekt. Das größte Problem bei der Sache ist vermutlich mein mangelndes Basiswissen über den Aufbau von Unicode ;-) - hat jemand eine Idee, wie ich ganz am Anfang schon die nicht-kyrillischen Zeichen aus dem String fischen und separat behandeln kann?

Möglicherweise ist das Ganze mit regulären Ausdrücken weit eleganter zu lösen, aber die sind für mich leider immer noch ein schwarzes Loch.

Danke fürs Nachdenken.

Gruß aus Köln-Ehrenfeld,

Elya

  1. Hallo,

    ich versuche, kyrillische utf-8-Zeichenketten nach bestimmten definierten Regeln in lateinische umzusetzen.
    Der Haken ist der Zweierschritt in dem substr-Ausdruck oben.

    Ja, wie viele octets ein Zeichen in UTF-8 hat, erkennst Du an den hochwertigsten bits des Startzeichens http://rfc.sunsite.dk/rfc/rfc3629.html
    ...
       Char. number range  |        UTF-8 octet sequence
          (hexadecimal)    |              (binary)
       --------------------+---------------------------------------------
       0000 0000-0000 007F | 0xxxxxxx
       0000 0080-0000 07FF | 110xxxxx 10xxxxxx
       0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
       0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
    ...

    Du musst also octet für octet (byte für byte) aus dem String nehmen und prüfen.

    Steht vorn eine 0, dann ist das octet das Zeichen.
    Steht vorn 110, dann besteht das Zeichen aus 2 octets.
    usw...

    Das gilt allerdings nur für UTF-8. Unicode kann auch in anderen encodings vorliegen http://www.unicode.org/faq/utf_bom.html.

    viele Grüße

    Axel

    1. Hallo Axel,

      danke für Deine Antwort.

      Ja, wie viele octets ein Zeichen in UTF-8 hat, erkennst Du an den hochwertigsten bits des Startzeichens http://rfc.sunsite.dk/rfc/rfc3629.html
         0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
      ...

      Du musst also octet für octet (byte für byte) aus dem String nehmen und prüfen.

      irgendwie habe ich geahnt, daß es nicht ganz trivial ist ;-) Ich probiere das heute abend mal aus, mal sehen, wie ich die octets aus dem String gefummelt bekomme.

      Gruß aus Köln-Ehrenfeld,

      Elya

      1. 你好 Elya,

        irgendwie habe ich geahnt, daß es nicht ganz trivial ist ;-) Ich probiere
        das heute abend mal aus, mal sehen, wie ich die octets aus dem String
        gefummelt bekomme.

        Ein Octet ist bei PHP in jedem Fall ein Byte und damit ein “Buchstabe”. Es
        ist also trivial, einzelne Octets zu betrachten, substr($str,$pos,1) reicht
        da aus, bzw. bei PHP geht ja auch $str{$pos}. Ueberpruefen, um welche
        Art Zeichen es sich handelt, kannst du dann recht einfach mit
        Bit-Operationen:

          
        if(ord($str{$pos}) < 0x80) {  
          # ein Zeichen lang  
        }  
        else if(ord($str{$pos}) < 0x2c) {  
          # illegale UTF-8-Sequenz, dieser Werte-Bereich kann nicht  
          # auftreten als Start-Sequenz  
        }  
        else if(ord($str{$pos}) < 0xe0) {  
          # zwei Byte lang  
        }  
        else if(ord($str{$pos}) < 0xf0) {  
          # drei Byte lang  
        }  
        else if(ord($str{$pos}) < 0xf8) {  
          # vier Byte lang  
        }  
        # Support fuer 6-Byte-UTF8, wie es im ISO/IEC beschrieben ist  
        else if(ord($str{$pos}) < 0xfc) {  
          # fuenf Byte lang  
        }  
        else if(ord($str{$pos}) < 0xfe) {  
          # 6 Byte lang  
        }  
        else {  
          # illegale UTF-8-Sequenz, dieser Werte-Bereich kann nicht  
          # auftreten als Start-Sequenz  
        }  
        
        

        Ist allerdings nicht getestet, sollte aber funktionieren.

        再见,
        克里斯蒂安

        --
        Coincidence?! I THINK NOT!!
  2. Hallo,

    Falls die Multibyte-String-Extension zur Verfügung steht - was allerdings eher selten der Fall ist - kann man einfach http://de2.php.net/manual/de/function.mb-substr.php verwenden.

    Mathias

    1. Hallo Mathias,

      Falls die Multibyte-String-Extension zur Verfügung steht - was allerdings eher selten der Fall ist - kann man einfach http://de2.php.net/manual/de/function.mb-substr.php verwenden.

      da ich einen guten Draht zu meinem Webserveradmin habe, steht es mir erstaunlicherweise zur Verfügung - das probiere ich auch heute abend aus. Danke Dir!

      Gruß aus Köln-Ehrenfeld,

      Elya