2011-12-13 12 views
21

Parece que MySQL does not support caracteres con más de 3 bytes en su juego de caracteres UTF-8 predeterminado.Cómo reemplazar/eliminar 4 (+) - caracteres de bytes de una cadena UTF-8 en PHP?

Entonces, en PHP, ¿cómo puedo deshacerme de los 4 caracteres (y más) bytes en una cadena y reemplazarlos por algo así como por algún otro personaje?

+1

¿Está seguro de que los datos con los que va a operar contendrán siempre caracteres que no encajan en el utf8 de 3 bytes de MySQL? – newtover

+1

¿Estás seguro de que incluso * hay * caracteres similares? 3 bytes te dan todo el Plano Bilingüe Básico; si necesita caracteres mucho más raros más allá de esto, considere otra codificación Unicode (por ejemplo, utf-16). – Piskvor

+1

El problema es que quiero evitar los otros, porque MySQL trunca textos en ese punto si alguien pone uno de esos caracteres especiales allí. – Franz

Respuesta

2

He aquí un ejemplo:

<?php 

mb_internal_encoding("UTF-8"); 

//utf8 string, 13 bytes, 9 utf8 chars, 7 ASCII, 1 in latin1, 1 outside the BMP 
$str = "qué \xF0\x9D\x92\xB3 tal"; 
$array = mbStringToArray($str); 
print "str: [$str] strlen:" . strlen($str) . " chars:" . count($array) . "\n"; 
$str1 = ""; 
foreach($array as $c) { 
    // print "$c : " . strlen($c) ."\n"; 
    $str1 .= strlen($c)<=3? $c : '?'; 
} 
print "[$str1]\n"; 


function mbStringToArray ($str) { 
    if (empty($str)) return false; 
    $len = mb_strlen($str); 
    $array = array(); 
    for ($i = 0; $i < $len; $i++) { 
     $array[] = mb_substr($str, $i, 1); 
    } 
    return $array; 
} 

O bien, un poco más compacto y eficiente:

<?php /// 

mb_internal_encoding("UTF-8"); 

//utf8 string, 13 bytes, 9 utf8 chars, 7 ASCII, 1 in latin1, 1 outside the BMP 
$str = "qué \xF0\x9D\x92\xB3 tal"; 
$str1 = trimOutsideBMP($str); 
print "original: [$str]\n"; 
print "trimmed: [$str1]\n"; 


// Replaces non-BMP characters in the UTF-8 string by a '?' character 
// Assumes UTF-8 default encoding (if not sure, call first mb_internal_encoding("UTF-8");) 
function trimOutsideBMP($str) { 
    if (empty($str)) return $str; 
    $len = mb_strlen($str); 
    $str1 = ''; 
    for ($i = 0; $i < $len; $i++) { 
     $c = mb_substr($str, $i, 1); 
     $str1 .= strlen($c) <= 3 ? $c : '?'; 
    } 
    return $str1; 
} 
+0

Oh, ¿debería haber mencionado que necesito una solución que no requiere la extensión 'mbstring'? – Franz

+0

Mmm eso es feo. Ver, por ejemplo, aquí para la inspiración: http://noteslog.com/post/full-utf-8-support-in-wordpress/ – leonbloy

1

encontré con esta pregunta cuando se trata de resolver mi propia emisión (Facebook escupe algunos emoticonos como 4 -bit caracteres, Amazon Mechanical Turk no acepta caracteres de 4 bytes).

Terminé usando esto, no requiere la extensión mbstring:

function remove_4_byte($string) { 
    $char_array = preg_split('/(?<!^)(?!$)/u', $string); 
    for($x=0;$x<sizeof($char_array);$x++) { 
     if(strlen($char_array[$x])>3) { 
      $char_array[$x] = ""; 
     } 
    } 
    return implode($char_array, ""); 
} 
+0

Por alguna razón no pude hacer que los demás funcionaran, este es el truco. – Mahn

9

Como las secuencias UTF-8 de 4 bytes siempre comienzan con los bytes 0xF0-0xF7, el siguiente debería funcionar:

$str = preg_replace('/[\xF0-\xF7].../s', '', $str); 

Como alternativa, puede utilizar preg_replace en modo UTF-8 pero esto probablemente será más lenta:

$str = preg_replace('/[\x{10000}-\x{10FFFF}]/u', '', $str); 

Esto funciona porque las secuencias UTF-8 de 4 bytes se usan para puntos de código en los planos Unicode suplementarios a partir de 0x10000.

1

A continuación cambio de función 3 y 4 caracteres bytes de UTF-8 cadena a '#':

function remove3and4bytesCharFromUtf8Str($str) { 
     return preg_replace('/([\xF0-\xF7]...)|([\xE0-\xEF]..)/s', '#', $str); 
    } 
0

Aquí está mi aplicación para filtrar los caracteres de 4 bytes

$string = preg_replace_callback(
    '/./u', 
    function (array $match) { 
     return strlen($match[0]) >= 4 ? null : $match[0]; 
    }, 
    $string 
); 

puede ajustarlo y reemplazar null (que elimina el carácter) con alguna cadena sustituta. También puede reemplazar >= 4 con alguna otra verificación de longitud de byte.

Cuestiones relacionadas