Làm cách nào để giải mã các chuỗi thoát Unicode như “\ u00ed” thành các ký tự được mã hóa UTF-8 thích hợp?


96

Có một hàm nào trong PHP có thể giải mã các chuỗi thoát Unicode như " \u00ed" thành " í" và tất cả các lần xuất hiện tương tự khác không?

Tôi đã tìm thấy câu hỏi tương tự ở đây nhưng dường như không hoạt động.

Câu trả lời:


169

Thử cái này:

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

Trong trường hợp đó là kiểu C / C ++ / Java / Json dựa trên 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
Tôi đặt "\ u00ed" ở đâu?
Docstero

2
@Docstero: Biểu thức chính quy sẽ khớp với bất kỳ chuỗi nào có \ubốn chữ số thập lục phân theo sau.
Gumbo

9
Hàm này không thể xử lý các ký tự bổ sung vì chúng không thể được biểu diễn trong UCS-2.
Artefacto

3
@gumbo Bạn gọi hoặc sử dụng chức năng này như thế nào?
Demodave

2
Tôi đã tìm thấy cách của mình ở đây khi tôi đã cài đặt đầu ra của mình, nhưng tôi đang xem đầu ra với json_encode () và thú vị là json_encode () mặc định sẽ làm rối đầu ra, vì vậy hãy sử dụng json_encode ($ theDict, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
Tom Andersen

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

44
Nó thậm chí không cần trình bao bọc đối tượng:json_decode('"' . $text . '"')
dối trá

3
Cảm ơn. Đây dường như là CÁCH TIÊU CHUẨN , đúng hơn là câu trả lời được chấp nhận.
T.Todua

Điều thú vị là, điều này cũng làm việc cho các tổ chức phức tạp như khuôn mặt cười ... json_decode('{"t":"\uD83D\uDE0A"}')là 😊
DynamicDan

2
@deceze bạn nên bao gồm thực tế $textcó thể bao gồm dấu ngoặc kép. Vì vậy, một phiên bản sửa đổi sẽ là: json_decode('"'.str_replace('"', '\\"', $text).'"'). Cảm ơn sự giúp đỡ của bạn :-)
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);
}

Cảm ơn bạn. Điều này dường như hoạt động với ký tự bổ sung, chẳng hạn như😍
c00000fd

3

Đây là một cách tiếp cận búa tạ để thay thế UNICODE thô bằng HTML. Tôi chưa thấy bất kỳ nơi nào khác đưa ra giải pháp này, nhưng tôi cho rằng những người khác đã gặp vấn đề này.

Áp dụng hàm str_replace này cho RAW JSON , trước khi làm bất kỳ điều gì khác.

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

Điều này sẽ không mất nhiều thời gian như bạn nghĩ và điều này sẽ thay thế BẤT KỲ mã unicode nào bằng HTML.

Tất nhiên điều này có thể được giảm bớt nếu bạn biết các loại unicode đang được trả về trong JSON.

Ví dụ, mã của tôi nhận được rất nhiều mũi tên và dingbat unicode. Chúng nằm giữa 8448 và 11263. Vì vậy, mã sản xuất của tôi trông giống như sau:

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

Bạn có thể tra cứu các khối Unicode theo loại tại đây: http://unicode-table.com/en/ Nếu bạn biết mình đang dịch tiếng Ả Rập hoặc Telegu hoặc bất cứ thứ gì, bạn chỉ có thể thay thế các mã đó, không phải tất cả 65.000.

Bạn có thể áp dụng cùng một chiếc búa tạ này để mã hóa đơn giản:

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

1

Ngoài ra còn có một giải pháp:
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

sửa các giá trị json, nó thêm \ trước u {xxx} vào tất cả + ""

  $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);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.