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.

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

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] => í )

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


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

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

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;
}

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);
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.