"\ u00ed"와 같은 유니 코드 이스케이프 시퀀스를 올바른 UTF-8 인코딩 문자로 디코딩하는 방법은 무엇입니까?


97

" \u00ed"에서 " í"및 기타 모든 유사한 발생과 같은 유니 코드 이스케이프 시퀀스를 디코딩 할 수있는 함수가 PHP에 있습니까?

여기 에서 비슷한 질문을 찾았 지만 작동하지 않는 것 같습니다.

답변:


169

이 시도:

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

UTF-16 기반 C / C ++ / Java / Json 스타일 인 경우 :

$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
"\ u00ed"를 어디에 입력합니까?
Docstero

2
@Docstero : 정규식은 \u4 개의 16 진수 가 뒤 따르는 모든 시퀀스와 일치합니다 .
Gumbo

9
이 함수는 UCS-2로 표현할 수 없기 때문에 보충 문자를 처리 할 수 ​​없습니다.
Artefacto

3
@gumbo이 함수를 어떻게 호출하거나 사용합니까?
Demodave

2
내 출력에서 ​​내 길을 찾았지만 json_encode ()로 출력을보고 있었고 재미있게도 기본 json_encode ()가 출력을 폐기하므로 json_encode ($ theDict, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
Tom Andersen

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

44
개체 래퍼도 필요하지 않습니다.json_decode('"' . $text . '"')
deceze

3
감사. 이것은 표준 방식으로 보이지만 오히려 받아 들여지는 대답입니다.
T.Todua 2016

흥미롭게도 이것은 웃는 얼굴과 같은 복잡한 개체에도 적용됩니다 ... json_decode('{"t":"\uD83D\uDE0A"}')is 😊
DynamicDan

2
@deceze $text는 큰 따옴표를 포함 할 수 있다는 사실을 포함해야 합니다. 따라서 수정 된 버전은 다음과 같습니다 json_decode('"'.str_replace('"', '\\"', $text).'"').. 도와 주셔서 감사합니다 :-)
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);
}

감사합니다. 이것은😍
c00000fd

3

이것은 원시 UNICODE를 HTML로 대체하는 쇠약 한 접근 방식입니다. 이 솔루션을 넣을 다른 곳을 보지 못했지만 다른 사람들 이이 문제를 가지고 있다고 가정합니다.

다른 작업을 수행하기 전에이 str_replace 함수를 RAW JSON에 적용하십시오 .

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

이것은 생각만큼 오래 걸리지 않을 것이며 모든 유니 코드를 HTML로 대체 할 것입니다.

물론 JSON에서 반환되는 유니 코드 유형을 알고 있으면이 값을 줄일 수 있습니다.

예를 들어, 내 코드는 많은 화살표와 dingbat 유니 코드를 얻었습니다. 이것들은 8448에서 11263 사이입니다. 그래서 내 프로덕션 코드는 다음과 같습니다.

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

여기에서 유형별로 유니 코드 블록을 찾을 수 있습니다. http://unicode-table.com/en/ 아랍어 나 Telegu 등을 번역하는 것을 알고 있다면 65,000 개가 아닌 해당 코드 만 바꿀 수 있습니다.

이 동일한 슬레지 해머를 간단한 인코딩에 적용 할 수 있습니다.

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

1

해결책도 있습니다 :
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

json 값을 수정하면 모든 + ""에 u {xxx} 앞에 \를 추가합니다.

  $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);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.