Já falamos sobre Unicode, e sabemos que os símbolos UTF-8 podem precisar de 1 a 4 bytes devido ao número de símbolos definidos pela tabela Unicode e pelo funcionamento do algoritimo de codificação/decodificação UTF-8.
Para ajudar em algumas operações com strings com texto em UTF-8, pode ser necessário utilizar um recurso extra. A seguir, são disponíveis algumas funções para trabalhar com UTF-8:
Linguagem: PHP
Copyright 2010 Rubens Takiguti Ribeiro
Licença: LGPL 3 ou superior
/** * Retorna o codigo de um caracter em UTF-8 * @param string $c: caractere UTF-8 (de 1 a 4 bytes) * @return int Codigo do caractere informado */ function ord_utf8($c) { // Caracteres UTF-8 tem entre 8 e 32 bits conforme tabela, sendo de 7 a 21 significativos // http://tools.ietf.org/html/rfc3629 // Intervalo | Sequencia de octetos // (hexadecimal) | (binario) // --------------------+-------------------------------------- // 00000000 - 0000007F | 0xxxxxxx // 00000080 - 000007FF | 110xxxxx 10xxxxxx // 00000800 - 0000FFFF | 1110xxxx 10xxxxxx 10xxxxxx // 00010000 - 0010FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx $tam_real = strlen($c); /// 1 - Obter o representante decimal de cada byte do caractere recebido $vt_ord = array(); for ($i = $tam_real - 1; $i >= 0; $i--) { $vt_ord[$i] = ord($c[$i]); } /// 2 - Checar se o caracter e' um ASCII padrao (1 byte): tem 7 bits significativos if ($vt_ord[0] <= 0x7F) { // byte1 <= 01111111 return $vt_ord[0]; } /// 3 - Validar caracter e obter os bits necessarios // Se espera 2 bytes: tem 8 a 11 bits significativos if ($vt_ord[0] <= 0xDF) { // byte1 <= 11011111 if ($tam_real == 2 && // tem 2 bytes (($vt_ord[1] & 0xC0) == 0x80)) { // byte2 & 11000000 == 10000000 (byte2 == 10xxxxxx) return ($vt_ord[1] & 0x3F) | // byte2 & 00111111 (6 bits) (($vt_ord[0] & 0x1F) << 6); // byte1 & 00011111 (+ 5 bits) } // Se espera 3 bytes: tem 12 a 16 bits significativos } elseif ($vt_ord[0] <= 0xEF) { // byte1 <= 11101111 if ($tam_real == 3 && // tem 3 bytes (($vt_ord[1] & 0xC0) == 0x80) && // byte2 & 11000000 == 10000000 (byte2 == 10xxxxxx) (($vt_ord[2] & 0xC0) == 0x80)) { // byte3 & 11000000 == 10000000 (byte3 == 10xxxxxx) return ($vt_ord[2] & 0x3F) | // byte3 & 00111111 (6 bits) (($vt_ord[1] & 0x3F) << 6) | // byte2 & 00111111 (+ 6 bits) (($vt_ord[0] & 0x1F) << 12); // byte1 & 00011111 (+ 5 bits) } // Se espera 4 bytes: tem 17 a 21 bits significativos } elseif ($vt_ord[0] <= 0xF4) { // byte1 <= 11110111 if ($tam_real == 4 && // tem 4 bytes (($vt_ord[1] & 0xC0) == 0x80) && // byte2 & 11000000 == 10000000 (byte2 == 10xxxxxx) (($vt_ord[2] & 0xC0) == 0x80) && // byte3 & 11000000 == 10000000 (byte3 == 10xxxxxx) (($vt_ord[3] & 0xC0) == 0x80)) { // byte4 & 11000000 == 10000000 (byte4 == 10xxxxxx) return ($vt_ord[3] & 0x3F) | // byte4 & 00111111 (6 bits) (($vt_ord[2] & 0x3F) << 6) | // byte3 & 00111111 (+ 6 bits) (($vt_ord[1] & 0x3F) << 12) | // byte2 & 00111111 (+ 6 bits) (($vt_ord[0] & 0x1F) << 18); // byte1 & 00011111 (+ 5 bits) } } // Se o UTF-8 informado e' invalido $vt_binario = array(); for ($i = 0; $i < $tam_real; $i++) { $vt_binario[] = sprintf('%08d', decbin($vt_ord[$i])); } $binario = implode(' ', $vt_binario); trigger_error('Caracter UTF-8 invalido: '.$binario, E_USER_NOTICE); return false; } /** * Gera um caractere UTF-8 a partir do seu codigo (7 a 21 bits) * @param int $ord: codigo do caractere * @return string caractere UTF-8 */ function chr_utf8($ord) { // Tem 1 byte (7 bits significativos) if ($ord <= 0x7F) { return chr($ord); // Tem 2 bytes (11 bits significativos = 5 + 6) } elseif ($ord <= 0x7FF) { return chr((($ord >> 6) & 0x1F) | 0xC0). // ((ord >> 6) & 00011111) | 11000000 chr(( $ord & 0x3F) | 0x80); // ( ord & 00111111) | 10000000 // Tem 3 bytes (16 bits significativos = 4 + 6 + 6) } elseif ($ord <= 0xFFFF) { return chr((($ord >> 12) & 0xF) | 0xE0). // ((ord >> 12) & 00001111) | 11100000 chr(( ($ord >> 6) & 0x3F) | 0x80). // ( (ord >> 6) & 00111111) | 10000000 chr(( $ord & 0x3F) | 0x80); // ( ord & 00111111) | 10000000 // Tem 4 bytes (21 bits significativos = 3 + 6 + 6 + 6) } elseif ($ord <= 0x10FFFF) { return chr((($ord >> 18) & 0x7) | 0xF0). // ((ord >> 18) & 00000111) | 11110000 chr((($ord >> 12) & 0x3F) | 0x80). // ((ord >> 12) & 00111111) | 10000000 chr((($ord >> 6) & 0x3F) | 0x80). // ( (ord >> 6) & 00111111) | 10000000 chr(( $ord & 0x3F) | 0x80); // ( ord & 00111111) | 10000000 } trigger_error('O codigo '.$ord.' nao pode ser representado em UTF-8', E_USER_NOTICE); return false; } /** * Retorna o tamanho esperado de um caracter UTF-8 * @param string $c: caractere UTF-8 (de 1 a 4 bytes) * @return int tamanho do caractere em bytes */ function tamanho_utf8($c) { $ord = ord($c[0]); if ($ord <= 0x7F) { // byte <= 01111111 return 1; } elseif ($ord <= 0xDF) { // byte <= 11011111 return 2; } elseif ($ord <= 0xEF) { // byte <= 11101111 return 3; } elseif ($ord <= 0xF4) { // byte <= 11110111 return 4; } trigger_error('O caractere informado nao representa um UTF-8', E_USER_NOTICE); return false; } /** * Retorna um caracter UTF-8 de uma posicao da string UTF-8 * @param string $str: string codificada em UTF-8 * @param int $pos: posicao do caracter desejado * @return string caractere da posicao indicada */ function get_char_utf8($str, $pos) { $len = strlen($str); $tam_caractere = 0; $caractere = 0; for ($i = 0; $i < $len; $i += $tam_caractere, $caractere++) { // Checar o tamanho do caractere UTF-8 $tam_caractere = tamanho_utf8($str[$i]); if ($caractere == $pos) { return substr($str, $i, $tam_caractere); } } trigger_error('Nao existe a posicao '.$pos.' na string "'.$str.'"', E_USER_NOTICE); return false; }
Com estas funções, você é capaz, inclusive, de implementar um html entities para caracteres unicode. Por exemplo, para gerar entities dos símbolos unicode de uma string, exceto os símbolos ASCII. Basta fazer:
$string = 'Atenção'; $string_codificada = html_entities_utf8($string); echo $string_codificada; // Imprime Atenção /** * Converte os caracteres UTF-8 para notacao com entities * @param string $string Texto unicode * @return string Texto em HTML entities */ function html_entities_utf8($string) { $saida = ''; $len = strlen($string); $i = 0; while ($i < $len && $char_len = tamanho_utf8(substr($string, $i, 4))) { $char = substr($string, $i, $char_len); if ($char_len == 1) { $saida .= $char; } else { $ord = ord_utf8($char); $saida .= '&#' . $ord . ';'; } $i += $char_len; } return $saida; }
0 comentários
Postar um comentário
Nota: fique a vontade para expressar o que achou deste artigo ou do blog.
Dica: para acompanhar as respostas, acesse com uma conta do Google e marque a opção "Notifique-me".
Atenção: o blogger não permite inclusão de tags nos comentários, por isso, use algum site externo para postar seu código com dúvidas e deixe o link aqui. Exemplo: pastebin.com