Comment décoder les séquences d'échappement Unicode telles que «\ u00ed» en caractères codés UTF-8 appropriés?

97

Existe-t-il une fonction en PHP qui peut décoder des séquences d'échappement Unicode comme " \u00ed" to " í" et toutes les autres occurrences similaires?

J'ai trouvé une question similaire ici mais cela ne semble pas fonctionner.

Docstero
la source

Réponses:

169

Essaye ça:

$str = preg_replace_callback('/\\\\u([0-9a-fA-F]{4})/', function ($match) {
    return mb_convert_encoding(pack('H*', $match[1]), 'UTF-8', 'UCS-2BE');
}, $str);

Dans le cas où il s'agit de style C / C ++ / Java / Json basé sur UTF-16:

$str = preg_replace_callback('/\\\\u([0-9a-fA-F]{4})/', function ($match) {
    return mb_convert_encoding(pack('H*', $match[1]), 'UTF-8', 'UTF-16BE');
}, $str);
Gombo
la source
1
Où dois-je mettre "\ u00ed"?
Docstero
2
@Docstero: L'expression régulière correspondra à n'importe quelle séquence de \usuivie de quatre chiffres hexadécimaux.
Gumbo
9
Cette fonction ne peut pas traiter les caractères supplémentaires car ils ne peuvent pas être représentés dans UCS-2.
Artefacto
3
@gumbo Comment appeler ou utiliser cette fonction?
Demodave
2
J'ai trouvé mon chemin ici comme je l'avais \ u00a0 trouvé dans ma sortie, mais je regardais la sortie avec json_encode () et assez curieusement, le json_encode () par défaut supprimera la sortie, utilisez donc json_encode ($ theDict, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
Tom Andersen
71
print_r(json_decode('{"t":"\u00ed"}')); // -> stdClass Object ( [t] => í )
2BJ
la source
44
Il n'a même pas besoin du wrapper d'objet:json_decode('"' . $text . '"')
deceze
3
Merci. Cela semble être une solution STANDARD , plutôt qu'une réponse acceptée.
T.Todua
Fait intéressant, cela fonctionne également pour les entités complexes comme les visages souriants ... json_decode('{"t":"\uD83D\uDE0A"}')est 😊
DynamicDan
2
@deceze vous devez inclure le fait qui $textpeut inclure des guillemets doubles. Ainsi , une version révisée serait: json_decode('"'.str_replace('"', '\\"', $text).'"'). Merci pour votre aide :-)
Yvan
11
$str = '\u0063\u0061\u0074'.'\ud83d\ude38';
$str2 = '\u0063\u0061\u0074'.'\ud83d';

// U+1F638
var_dump(
    "cat\xF0\x9F\x98\xB8" === escape_sequence_decode($str),
    "cat\xEF\xBF\xBD" === escape_sequence_decode($str2)
);

function escape_sequence_decode($str) {

    // [U+D800 - U+DBFF][U+DC00 - U+DFFF]|[U+0000 - U+FFFF]
    $regex = '/\\\u([dD][89abAB][\da-fA-F]{2})\\\u([dD][c-fC-F][\da-fA-F]{2})
              |\\\u([\da-fA-F]{4})/sx';

    return preg_replace_callback($regex, function($matches) {

        if (isset($matches[3])) {
            $cp = hexdec($matches[3]);
        } else {
            $lead = hexdec($matches[1]);
            $trail = hexdec($matches[2]);

            // http://unicode.org/faq/utf_bom.html#utf16-4
            $cp = ($lead << 10) + $trail + 0x10000 - (0xD800 << 10) - 0xDC00;
        }

        // https://tools.ietf.org/html/rfc3629#section-3
        // Characters between U+D800 and U+DFFF are not allowed in UTF-8
        if ($cp > 0xD7FF && 0xE000 > $cp) {
            $cp = 0xFFFD;
        }

        // https://github.com/php/php-src/blob/php-5.6.4/ext/standard/html.c#L471
        // php_utf32_utf8(unsigned char *buf, unsigned k)

        if ($cp < 0x80) {
            return chr($cp);
        } else if ($cp < 0xA0) {
            return chr(0xC0 | $cp >> 6).chr(0x80 | $cp & 0x3F);
        }

        return html_entity_decode('&#'.$cp.';');
    }, $str);
}
masakielastic
la source
Je vous remercie. Cela semble fonctionner avec des caractères supplémentaires, tels que😍
c00000fd
3

Il s'agit d'une approche de masse pour remplacer UNICODE brut par du HTML. Je n'ai vu aucun autre endroit pour mettre cette solution, mais je suppose que d'autres ont eu ce problème.

Appliquez cette fonction str_replace au JSON RAW avant de faire autre chose.

function unicode2html($str){
    $i=65535;
    while($i>0){
        $hex=dechex($i);
        $str=str_replace("\u$hex","&#$i;",$str);
        $i--;
     }
     return $str;
}

Cela ne prendra pas autant de temps que vous le pensez, et cela remplacera TOUT UNICODE par HTML.

Bien sûr, cela peut être réduit si vous connaissez les types Unicode qui sont renvoyés dans le JSON.

Par exemple, mon code recevait beaucoup de flèches et de dingbat unicode. Ce sont entre 8448 et 11263. Donc mon code de production ressemble à:

$i=11263;
while($i>08448){
    ...etc...

Vous pouvez rechercher les blocs Unicode par type ici: http://unicode-table.com/en/ Si vous savez que vous traduisez l'arabe ou Telegu ou autre, vous pouvez simplement remplacer ces codes, pas tous les 65 000.

Vous pouvez appliquer ce même marteau à un encodage simple:

 $str=str_replace("\u$hex",chr($i),$str);
Nemo Noman
la source
1

Il existe également une solution:
http://www.welefen.com/php-unicode-to-utf8.html

function entity2utf8onechar($unicode_c){
    $unicode_c_val = intval($unicode_c);
    $f=0x80; // 10000000
    $str = "";
    // U-00000000 - U-0000007F:   0xxxxxxx
    if($unicode_c_val <= 0x7F){         $str = chr($unicode_c_val);     }     //U-00000080 - U-000007FF:  110xxxxx 10xxxxxx
    else if($unicode_c_val >= 0x80 && $unicode_c_val <= 0x7FF){         $h=0xC0; // 11000000
        $c1 = $unicode_c_val >> 6 | $h;
        $c2 = ($unicode_c_val & 0x3F) | $f;
        $str = chr($c1).chr($c2);
    } else if($unicode_c_val >= 0x800 && $unicode_c_val <= 0xFFFF){         $h=0xE0; // 11100000
        $c1 = $unicode_c_val >> 12 | $h;
        $c2 = (($unicode_c_val & 0xFC0) >> 6) | $f;
        $c3 = ($unicode_c_val & 0x3F) | $f;
        $str=chr($c1).chr($c2).chr($c3);
    }
    //U-00010000 - U-001FFFFF:  11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
    else if($unicode_c_val >= 0x10000 && $unicode_c_val <= 0x1FFFFF){         $h=0xF0; // 11110000
        $c1 = $unicode_c_val >> 18 | $h;
        $c2 = (($unicode_c_val & 0x3F000) >>12) | $f;
        $c3 = (($unicode_c_val & 0xFC0) >>6) | $f;
        $c4 = ($unicode_c_val & 0x3F) | $f;
        $str = chr($c1).chr($c2).chr($c3).chr($c4);
    }
    //U-00200000 - U-03FFFFFF:  111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
    else if($unicode_c_val >= 0x200000 && $unicode_c_val <= 0x3FFFFFF){         $h=0xF8; // 11111000
        $c1 = $unicode_c_val >> 24 | $h;
        $c2 = (($unicode_c_val & 0xFC0000)>>18) | $f;
        $c3 = (($unicode_c_val & 0x3F000) >>12) | $f;
        $c4 = (($unicode_c_val & 0xFC0) >>6) | $f;
        $c5 = ($unicode_c_val & 0x3F) | $f;
        $str = chr($c1).chr($c2).chr($c3).chr($c4).chr($c5);
    }
    //U-04000000 - U-7FFFFFFF:  1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
    else if($unicode_c_val >= 0x4000000 && $unicode_c_val <= 0x7FFFFFFF){         $h=0xFC; // 11111100
        $c1 = $unicode_c_val >> 30 | $h;
        $c2 = (($unicode_c_val & 0x3F000000)>>24) | $f;
        $c3 = (($unicode_c_val & 0xFC0000)>>18) | $f;
        $c4 = (($unicode_c_val & 0x3F000) >>12) | $f;
        $c5 = (($unicode_c_val & 0xFC0) >>6) | $f;
        $c6 = ($unicode_c_val & 0x3F) | $f;
        $str = chr($c1).chr($c2).chr($c3).chr($c4).chr($c5).chr($c6);
    }
    return $str;
}
function entities2utf8($unicode_c){
    $unicode_c = preg_replace("/\&\#([\da-f]{5})\;/es", "entity2utf8onechar('\\1')", $unicode_c);
    return $unicode_c;
}
jianyong
la source
1

corriger les valeurs json, c'est ajouter \ avant u {xxx} à tous + ""

  $item = preg_replace_callback('/"(.+?)":"(u.+?)",/', function ($matches) {
        $matches[2] = preg_replace('/(u)/', '\u', $matches[2]);
            $matches[2] = preg_replace('/(")/', '&quot;', $matches[2]); 
            $matches[2] = json_decode('"' . $matches[2] . '"'); 
            return '"' . $matches[1] . '":"' . $matches[2] . '",';
        }, $item);
orel
la source