Caractere Unicode na string PHP

164

Esta pergunta parece embaraçosamente simples, mas não consegui encontrar uma resposta.

Qual é o PHP equivalente à seguinte linha de código C #?

string str = "\u1000";

Este exemplo cria uma sequência com um único caractere Unicode cujo "valor numérico Unicode" é 1000 em hexadecimal (4096 em decimal).

Ou seja, no PHP, como posso criar uma string com um único caractere Unicode cujo "valor numérico Unicode" é conhecido?

Telaclavo
fonte
4
@diEcho: isso é apenas para caracteres Unicode correspondentes, mas o OP deseja criar para esses caracteres.
Stefan Gehrig

Respostas:

178

Como o JSON suporta diretamente a \uxxxxsintaxe, a primeira coisa que me vem à mente é:

$unicodeChar = '\u1000';
echo json_decode('"'.$unicodeChar.'"');

Outra opção seria usar mb_convert_encoding()

echo mb_convert_encoding('က', 'UTF-8', 'HTML-ENTITIES');

ou faça uso do mapeamento direto entre UTF-16BE (big endian) e o ponto de código Unicode:

echo mb_convert_encoding("\x10\x00", 'UTF-8', 'UTF-16BE');
Stefan Gehrig
fonte
9
JSON não é JavaScript.
Gumbo
4
@ Gumbo: Eu sei disso, mas não faz nenhuma diferença aqui. Javascript e JSON suportam a \uxxxxsintaxe Unicode para que você possa usar json_decodepara trabalhar em uma representação de sequência JSON criada artificialmente. Eu mudei a redação para esclarecer isso.
Stefan Gehrig
3
Ok, então a formulação estrita de uma resposta para minha pergunta é: $ str = json_decode ('"\ u1000"'); Obrigado.
Telaclavo 19/05/11
Tentei echo json_decode('\u201B');Quais referes a uma única citação revertidos No entanto, não está funcionando, o que significa que nenhuma saída (mesmo canalizado para hd)
hek2mgl
4
Você precisa echo json_decode('"\u201B"');. Aspas duplas no símbolo unicode são obrigatórias.
23414 Stefan Gehrig
162

O PHP 7.0.0 introduziu a sintaxe "escape de ponto de código Unicode" .

Agora é possível escrever caracteres Unicode facilmente usando uma cadeia de caracteres com aspas duplas ou heredoc , sem chamar nenhuma função.

$unicodeChar = "\u{1000}";
Blackhole
fonte
Isto pode ser utilizado da seguinte forma: wordwrap($longLongText, 20, "\u{200B}", true);( espaço de largura zero é)
sanmai
5
Acredito que o OP queria essa resposta, não a resposta aceita. De qualquer forma, quando procurei "Unicode no PHP", era porque eu queria essa resposta, não a resposta aceita. Talvez "\ u {abcd}" não existisse quando esta pergunta foi feita pela primeira vez. Nesse caso, a resposta aceita agora deve ser movida.
Adam Chalcraft 29/05/19
23

Gostaria de saber por que ninguém mencionou isso ainda, mas você pode fazer uma versão quase equivalente usando seqüências de escape em seqüências de caracteres entre aspas duplas :

\x[0-9A-Fa-f]{1,2}

A sequência de caracteres que corresponde à expressão regular é um caractere em notação hexadecimal.

Exemplo ASCII:

<?php
    echo("\x48\x65\x6C\x6C\x6F\x20\x57\x6F\x72\x6C\x64\x21");
?>

Olá Mundo!

Portanto, para o seu caso, tudo o que você precisa fazer é $str = "\x30\xA2";. Mas estes são bytes , não caracteres. A representação em bytes do ponto de código Unicode coincide com o big endian UTF-16, para que possamos imprimi-lo diretamente da seguinte forma:

<?php
    header('content-type:text/html;charset=utf-16be');
    echo("\x30\xA2");
?>

Se você estiver usando uma codificação diferente, precisará alterar os bytes de acordo (principalmente com uma biblioteca, embora possível à mão também).

Exemplo pequeno de endian UTF-16:

<?php
    header('content-type:text/html;charset=utf-16le');
    echo("\xA2\x30");
?>

Exemplo UTF-8:

<?php
    header('content-type:text/html;charset=utf-8');
    echo("\xE3\x82\xA2");
?>

Há também a packfunção, mas você pode esperar que seja lenta.

Pacerier
fonte
Perfeito para quando copiar / colar um caractere de marcador (\ xE2 \ x80 \ xA2) pode resultar em um erro de codificação UTF-8 no documento de origem. Obrigado.
jimp
21

O PHP não conhece essas seqüências de escape Unicode. Mas, como as seqüências de escape desconhecidas permanecem inalteradas, você pode escrever sua própria função que converte essas seqüências de escape Unicode:

function unicodeString($str, $encoding=null) {
    if (is_null($encoding)) $encoding = ini_get('mbstring.internal_encoding');
    return preg_replace_callback('/\\\\u([0-9a-fA-F]{4})/u', create_function('$match', 'return mb_convert_encoding(pack("H*", $match[1]), '.var_export($encoding, true).', "UTF-16BE");'), $str);
}

Ou com uma expressão de função anônima em vez de create_function:

function unicodeString($str, $encoding=null) {
    if (is_null($encoding)) $encoding = ini_get('mbstring.internal_encoding');
    return preg_replace_callback('/\\\\u([0-9a-fA-F]{4})/u', function($match) use ($encoding) {
        return mb_convert_encoding(pack('H*', $match[1]), $encoding, 'UTF-16BE');
    }, $str);
}

Seu uso:

$str = unicodeString("\u1000");
quiabo
fonte
10
html_entity_decode('&#x30a8;', 0, 'UTF-8');

Isso também funciona. No entanto, a solução json_decode () é muito mais rápida (cerca de 50 vezes).

flori
fonte
Método simples, elegante, direto e totalmente seguro. +10
andreszs 13/09/19
7

Experimente o UTF-8 portátil :

$str = utf8_chr( 0x1000 );
$str = utf8_chr( '\u1000' );
$str = utf8_chr( 4096 );

Todos funcionam exatamente da mesma maneira. Você pode obter o ponto de código de um personagem com utf8_ord(). Leia mais sobre o Portable UTF-8 .

Hamid Sarfraz
fonte
3

Como mencionado por outros, o PHP 7 apresenta suporte para a \usintaxe Unicode diretamente.

Como também mencionado por outros, a única maneira de obter um valor de string a partir de qualquer descrição sensível de caracteres Unicode no PHP, é convertendo-o de outra coisa (por exemplo, análise JSON, análise HTML ou alguma outra forma). Mas isso tem um custo de desempenho em tempo de execução.

No entanto, há uma outra opção. Você pode codificar o caractere diretamente no PHP com \xescape binário. A \xsintaxe de escape também é suportada no PHP 5 .

Isso é especialmente útil se você preferir não inserir o caractere diretamente em uma string através de sua forma natural. Por exemplo, se é um caractere de controle invisível ou outro difícil de detectar em branco.

Primeiro, um exemplo de prova:

// Unicode Character 'HAIR SPACE' (U+200A)
$htmlEntityChar = "&#8202;";
$realChar = html_entity_decode($htmlEntityChar);
$phpChar = "\xE2\x80\x8A";
echo 'Proof: ';
var_dump($realChar === $phpChar); // bool(true)

Observe que, conforme mencionado por Pacerier em outra resposta, esse código binário é exclusivo para uma codificação de caracteres específica. No exemplo acima, \xE2\x80\x8Aé a codificação binária para U + 200A em UTF-8.

A próxima pergunta é: como você vai U+200Apara \xE2\x80\x8A?

Abaixo está um script PHP para gerar a sequência de escape para qualquer caractere, com base em uma sequência JSON, entidade HTML ou qualquer outro método, uma vez que você a possui como uma sequência nativa.

function str_encode_utf8binary($str) {
    /** @author Krinkle 2018 */
    $output = '';
    foreach (str_split($str) as $octet) {
        $ordInt = ord($octet);
        // Convert from int (base 10) to hex (base 16), for PHP \x syntax
        $ordHex = base_convert($ordInt, 10, 16);
        $output .= '\x' . $ordHex;
    }
    return $output;
}

function str_convert_html_to_utf8binary($str) {
    return str_encode_utf8binary(html_entity_decode($str));
}
function str_convert_json_to_utf8binary($str) {
    return str_encode_utf8binary(json_decode($str));
}

// Example for raw string: Unicode Character 'INFINITY' (U+221E)
echo str_encode_utf8binary('∞') . "\n";
// \xe2\x88\x9e

// Example for HTML: Unicode Character 'HAIR SPACE' (U+200A)
echo str_convert_html_to_utf8binary('&#8202;') . "\n";
// \xe2\x80\x8a

// Example for JSON: Unicode Character 'HAIR SPACE' (U+200A)
echo str_convert_json_to_utf8binary('"\u200a"') . "\n";
// \xe2\x80\x8a
Timo Tijhof
fonte
0
function unicode_to_textstring($str){

    $rawstr = pack('H*', $str);

    $newstr =  iconv('UTF-16BE', 'UTF-8', $rawstr);
    return $newstr;
}

$ msg = '67714eac99c500200054006f006b0079006f002000530074006100740069006f006e003a0020';

echo unicode_to_textstring ($ str);

chings228
fonte