Bagaimana cara mendekode urutan escape Unicode seperti "\ u00ed" menjadi karakter yang dikodekan UTF-8 yang benar?


97

Apakah ada fungsi dalam PHP yang dapat mendekode urutan escape Unicode seperti " \u00ed" ke " í" dan semua kejadian serupa lainnya?

Saya menemukan pertanyaan serupa di sini tetapi tampaknya tidak berhasil.

Jawaban:


169

Coba ini:

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

Jika itu adalah gaya C / C ++ / Java / Json berbasis 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);

1
Di mana saya meletakkan "\ u00ed"?
Docstero

2
@Docstero: Ekspresi reguler akan cocok dengan urutan apa pun yang \udiikuti oleh empat digit heksadesimal.
Gumbo

9
Fungsi ini tidak dapat menangani karakter tambahan karena tidak dapat direpresentasikan di UCS-2.
Artefacto

3
@gumbo Bagaimana Anda memanggil atau menggunakan fungsi ini?
Demodave

2
Saya menemukan jalan saya di sini seperti yang saya lakukan di output saya, tetapi saya melihat output dengan json_encode () dan cukup lucu default json_encode () akan mengotori output jadi gunakan json_encode ($ theDict, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
Tom Andersen

71
print_r(json_decode('{"t":"\u00ed"}')); // -> stdClass Object ( [t] => í )

44
Ia bahkan tidak membutuhkan pembungkus objek:json_decode('"' . $text . '"')
menipu

3
Terima kasih. Tampaknya ini CARA STANDAR , daripada jawaban yang diterima.
T.Todua

Menariknya, ini juga berfungsi untuk entitas kompleks seperti wajah tersenyum ... json_decode('{"t":"\uD83D\uDE0A"}')adalah 😊
DynamicDan

2
@deceze Anda harus menyertakan fakta yang $textdapat menyertakan tanda kutip ganda. Jadi versi revisi akan: json_decode('"'.str_replace('"', '\\"', $text).'"'). Terima kasih atas bantuan Anda :-)
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);
}

Terima kasih. Ini sepertinya bekerja dengan karakter tambahan, seperti😍
c00000fd

3

Ini adalah pendekatan palu godam untuk mengganti UNICODE mentah dengan HTML. Saya belum melihat tempat lain untuk meletakkan solusi ini, tetapi saya berasumsi bahwa orang lain memiliki masalah ini.

Terapkan fungsi str_replace ini ke RAW JSON , sebelum melakukan apa pun.

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

Ini tidak akan memakan waktu selama yang Anda pikirkan, dan ini akan menggantikan UNICode APA PUN dengan HTML.

Tentu saja hal ini dapat dikurangi jika Anda mengetahui jenis unicode yang dikembalikan di JSON.

Misalnya kode saya mendapatkan banyak panah dan unicode dingbat. Ini antara 8448 dan 11263. Jadi kode produksi saya terlihat seperti:

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

Anda dapat mencari blok Unicode menurut ketik di sini: http://unicode-table.com/en/ Jika Anda tahu Anda sedang menerjemahkan bahasa Arab atau Telegu atau apa pun, Anda dapat mengganti kode tersebut, tidak semuanya 65.000.

Anda dapat menerapkan palu godam yang sama ini ke pengkodean sederhana:

 $str=str_replace("\u$hex",chr($i),$str);

1

Ada juga solusinya:
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

perbaiki nilai json, tambahkan \ sebelum u {xxx} ke semua + ""

  $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);
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.