Wie dekodiere ich Unicode-Escape-Sequenzen wie "\ u00ed" in richtige UTF-8-codierte Zeichen?

96

Gibt es in PHP eine Funktion, die Unicode-Escape-Sequenzen wie " \u00ed" bis " í" und alle anderen ähnlichen Vorkommen dekodieren kann ?

Ich habe hier eine ähnliche Frage gefunden, aber sie scheint nicht zu funktionieren.

Docstero
quelle

Antworten:

168

Versuche dies:

$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);

Falls es sich um einen UTF-16-basierten C / C ++ / Java / Json-Stil handelt:

$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);
Gumbo
quelle
1
Wo lege ich "\ u00ed"?
Docstero
2
@Docstero: Der reguläre Ausdruck entspricht einer beliebigen Folge \uvon vier hexadezimalen Ziffern.
Gumbo
9
Diese Funktion kann keine zusätzlichen Zeichen verarbeiten, da sie in UCS-2 nicht dargestellt werden können.
Artefacto
3
@gumbo Wie ruft man diese Funktion auf oder benutzt sie?
Demodave
2
Ich habe meinen Weg hierher gefunden, wie ich es in meiner Ausgabe getan hatte, aber ich habe die Ausgabe mit json_encode () betrachtet und komischerweise wird der Standard-json_encode () die Ausgabe in den Papierkorb werfen. Verwenden Sie also json_encode ($ theDict, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE).
Tom Andersen
71
print_r(json_decode('{"t":"\u00ed"}')); // -> stdClass Object ( [t] => í )
2BJ
quelle
44
Es braucht nicht einmal den Objekt-Wrapper:json_decode('"' . $text . '"')
Täuschung
3
Vielen Dank. Dies scheint eher ein STANDARDWEG zu sein als eine akzeptierte Antwort.
T.Todua
Interessanterweise funktioniert dies auch für komplexe Entitäten wie Smileys ... json_decode('{"t":"\uD83D\uDE0A"}')ist 😊
DynamicDan
2
@deceze Sie sollten die Tatsache einschließen, dass $textdoppelte Anführungszeichen enthalten können. Eine überarbeitete Version wäre also : json_decode('"'.str_replace('"', '\\"', $text).'"'). Vielen Dank für Ihre Hilfe :-)
Yvan
13

PHP 7+

Ab PHP 7 können Sie dazu die Unicode-Codepoint-Escape-Syntax verwenden.

echo "\u{00ed}";Ausgänge í.

Rabin Lama Dong
quelle
1
Vielen Dank! Viel einfacher als die anderen Antworten
Gus
10
$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);
}
masakielastisch
quelle
Danke dir. Dies scheint mit ergänzendem Charakter zu funktionieren, wie z. B.😍
c00000fd
3

Dies ist ein Vorschlaghammer-Ansatz zum Ersetzen von rohem UNICODE durch HTML. Ich habe keinen anderen Ort gesehen, an dem ich diese Lösung finden könnte, aber ich gehe davon aus, dass andere dieses Problem hatten.

Wenden Sie diese str_replace-Funktion auf RAW JSON an , bevor Sie etwas anderes tun.

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

Dies dauert nicht so lange, wie Sie denken, und ersetzt JEDEN Unicode durch HTML.

Dies kann natürlich reduziert werden, wenn Sie die Unicode-Typen kennen, die im JSON zurückgegeben werden.

Zum Beispiel bekam mein Code viele Pfeile und Dingbat-Unicode. Diese liegen zwischen 8448 und 11263. Mein Produktionscode sieht also so aus:

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

Sie können die Blöcke von Unicode nach Typ hier nachschlagen: http://unicode-table.com/de/ Wenn Sie wissen, dass Sie Arabisch oder Telegu oder was auch immer übersetzen, können Sie nur diese Codes ersetzen, nicht alle 65.000.

Sie können denselben Vorschlaghammer auf die einfache Codierung anwenden:

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

Es gibt auch eine Lösung:
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
quelle
1

Fix json Werte, es ist \ vor u {xxx} zu allen + "" hinzufügen

  $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
quelle