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.

Docstero
sumber

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);
Gumbo
sumber
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] => í )
2BJ
sumber
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
14

PHP 7+

Mulai PHP 7, Anda dapat menggunakan sintaks escape titik kode Unicode untuk melakukan ini.

echo "\u{00ed}";keluaran í.

Rabin Lama Dong
sumber
1
Terima kasih! Jauh lebih sederhana dari jawaban lainnya
Gus
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);
}
masakielastik
sumber
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);
Nemo Noman
sumber
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;
}
jianyong
sumber
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);
orel
sumber