2009-09-24 9 views
4
function seems_utf8($str) { 
$length = strlen($str); 
for ($i=0; $i < $length; $i++) { 
    $c = ord($str[$i]); 
    if ($c < 0x80) $n = 0; # 0bbbbbbb 
    elseif (($c & 0xE0) == 0xC0) $n=1; # 110bbbbb 
    elseif (($c & 0xF0) == 0xE0) $n=2; # 1110bbbb 
    elseif (($c & 0xF8) == 0xF0) $n=3; # 11110bbb 
    elseif (($c & 0xFC) == 0xF8) $n=4; # 111110bb 
    elseif (($c & 0xFE) == 0xFC) $n=5; # 1111110b 
    else return false; # Does not match any model 
    for ($j=0; $j<$n; $j++) { # n bytes matching 10bbbbbb follow ? 
    if ((++$i == $length) || ((ord($str[$i]) & 0xC0) != 0x80)) 
    return false; 
    } 
} 
return true; 
} 

Je suis arrivé ce code de Wordpress, je ne sais pas grand-chose à ce sujet, mais je voudrais savoir ce que happing exactement dans cette fonction.Vérifiez si une chaîne est codée en UTF-8

Si quelqu'un sait s'il vous plaît aidez-moi?

J'ai besoin de l'idée claire sur le code ci-dessus. Si l'explication ligne par ligne sera plus utile.

Répondre

8

J'utilise deux façons de vérifier si la chaîne est utf-8 (selon le cas):

mb_internal_encoding('UTF-8'); // always needed before mb_ functions, check note below 
if (mb_strlen($string) != strlen($string)) { 
/// not single byte 
} 

- OU -

if (preg_match('!\S!u', $string)) { 
// utf8 
} 

Pour la mb_internal_encoding - en raison d'une inconnue bogue dans php (version 5.3- (ne l'ai pas testé sur 5.3)) passer le codage en paramètre à la fonction mb_ ne fonctionne pas et le codage interne doit être paramétré avant toute utilisation des fonctions mb_.

+0

il suffit donc de faire 'mb_strlen ($ string, 'UTF-8')' t poule. –

7

Cet algorithme vérifie essentiellement si la séquence d'octets est conforme au modèle que vous pouvez voir dans Wikipedia article. La boucle for doit parcourir tous les octets au $str. ord obtient le nombre décimal de l'octet courant. Ce nombre est ensuite testé pour certaines propriétés.

Si le nombre est inférieur à 128 (0x80), il s'agit d'un caractère à un seul octet. Si elle est égale ou supérieure à 128, la longueur du caractère multi-octets est vérifiée. Cela peut être fait avec le premier caractère d'une séquence de caractères multi-octets. Si le premier octet commence par 110xxxxx, il s'agit d'un caractère de deux octets; 1110xxxx, c'est un caractère de trois octets, etc.

Je pense que les parties les plus cryptiques sont les expressions comme ($c & 0xE0) == 0xC0. C'est de vérifier si le nombre au format binaire a un motif spécifique. Je vais essayer d'expliquer comment cela fonctionne sur le même exemple.

Puisque tous les nombres que nous testons pour ce modèle sont égaux ou supérieurs à 0x80, le premier octet est toujours 1, donc le modèle est limité à au moins 1xxxxxxxx. Si nous alors faisons une sage bit et comparaison avec 11100000 (0xE0), nous obtenons ce ce résultat:

1xxxxxxx 
& 11100000 
= 1xx00000 

donc les bits à la position 5 et 6 (lecture de la droite, l'indice a commencé à 0) dépendent quel est notre numéro actuel. Pour avoir cette égale à 11000000, le 5ème bit doit être 0 et le 6ème bit doit être 1:

1xxxxxxx 
& 11100000 
≟ 11000000 
    ↓↓ 
→ 110xxxxx 

Cela signifie que les autres bits de notre numéro peut être arbitraire: 110xxxxx. Et c'est exactement ce que le modèle de l'article de Wikipedia prédit pour le premier octet d'un mot de caractère à deux octets.

Et enfin la boucle interne for est de vérifier la santé mentale des octets suivants d'un caractère multi-octets. Ceux-ci doivent tous commencer par 10xxxxxx.

6

Si vous connaissez un peu l'UTF-8, c'est une implémentation assez simple.

function seems_utf8($str) { 
# get length, for utf8 this means bytes and not characters 
$length = strlen($str); 

# we need to check each byte in the string 
for ($i=0; $i < $length; $i++) { 

    # get the byte code 0-255 of the i-th byte 
    $c = ord($str[$i]); 

    # utf8 characters can take 1-6 bytes, how much 
    # exactly is decoded in the first character if 
    # it has a character code >= 128 (highest bit set). 
    # For all <= 127 the ASCII is the same as UTF8. 
    # The number of bytes per character is stored in 
    # the highest bits of the first byte of the UTF8 
    # character. The bit pattern that must be matched 
    # for the different length are shown as comment. 
    # 
    # So $n will hold the number of additonal characters 

    if ($c < 0x80) $n = 0; # 0bbbbbbb 
    elseif (($c & 0xE0) == 0xC0) $n=1; # 110bbbbb 
    elseif (($c & 0xF0) == 0xE0) $n=2; # 1110bbbb 
    elseif (($c & 0xF8) == 0xF0) $n=3; # 11110bbb 
    elseif (($c & 0xFC) == 0xF8) $n=4; # 111110bb 
    elseif (($c & 0xFE) == 0xFC) $n=5; # 1111110b 
    else return false; # Does not match any model 

    # the code now checks the following additional bytes 
    # First in the if checks that the byte is really inside the 
    # string and running over the string end. 
    # The second just check that the highest two bits of all 
    # additonal bytes are always 1 and 0 (hexadecimal 0x80) 
    # which is a requirement for all additional UTF-8 bytes 

    for ($j=0; $j<$n; $j++) { # n bytes matching 10bbbbbb follow ? 
    if ((++$i == $length) || ((ord($str[$i]) & 0xC0) != 0x80)) 
    return false; 
    } 
} 
return true; 
} 

Par ailleurs. Sur PHP je suppose que c'est un facteur 50-100 plus lent qu'une fonction C donc vous ne devriez pas vraiment l'utiliser sur les chaînes longues et les systèmes de production.

0

trébuché sur ce poste, avait la même question .. mb_detect_encoding a montré utf-8, mais mb_check_encoding retourne faux ...

Pour résoudre ce problème, pour moi la solution était:

$cur_encoding = mb_detect_encoding($in_str) ; 
    if($cur_encoding == "UTF-8" && mb_check_encoding($in_str,"UTF-8")) 
    return $in_str; 
    else 
    return utf8_encode($in_str); 

il reçu de il: http://board.phpbuilder.com/showthread.php?10368156-mb_check_encoding%28-in_str-quot-UTF-8-quot-%29-return-different-results

SRY ne pouvait pas poster le lien correctement ....

Questions connexes