Sobre nós Guias Projetos Contactos
Админка
please wait

Os problemas de codificação de caracteres afetam aplicações que lidam com texto internacional. Desde mojibake (caracteres corrompidos) até corrupção de dados, os problemas de codificação podem destruir a integridade dos dados e a experiência do utilizador. Compreender os fundamentos da codificação e conhecer técnicas de recuperação é essencial para qualquer programador que trabalhe com dados de texto. Este guia aborda conversões de codificação na perspetiva de um programador sénior.

Porque a Codificação é Importante

Um tratamento correto da codificação permite:

  1. Integridade dos Dados: Texto armazenado e recuperado corretamente
  2. Internacionalização: Suporte para todas as línguas
  3. Interoperabilidade: Troca de dados entre sistemas
  4. Experiência do Utilizador: Sem caracteres corrompidos
  5. Conformidade Legal: Tratamento adequado dos dados do utilizador

Compreender Codificações de Caracteres

Codificações Comuns

CodificaçãoBytes/CarácterCaracteresCaso de Uso
ASCII1128Apenas inglês
ISO-8859-1 (Latin-1)1256Europa Ocidental
Windows-1251 (cp1251)1256Cirílico
Windows-12521256Windows Ocidental
UTF-81-41,112,064Universal (recomendado)
UTF-162-41,112,064Internos do Windows

Padrões de Bytes em UTF-8

O UTF-8 utiliza codificação de comprimento variável:

Range | Binary Pattern
------------------|------------------------------------
U+0000 to U+007F | 0xxxxxxx (1 byte)
U+0080 to U+07FF | 110xxxxx 10xxxxxx (2 bytes)
U+0800 to U+FFFF | 1110xxxx 10xxxxxx 10xxxxxx (3 bytes)
U+10000 to U+10FFFF| 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx (4 bytes)

Como Acontece o Mojibake

Original: "Привет" (Russian "Hello")
UTF-8 bytes: D0 9F D1 80 D0 B8 D0 B2 D0 B5 D1 82
Misinterpretation as cp1251:
D0 → Р
9F → (control char)
D1 → С...
Result: "Привет" → "Привет" (mojibake)

Problemas de Codificação em Bases de Dados

Configuração de Codificação no MySQL

-- Verificar as definições atuais
SHOW VARIABLES LIKE 'character_set%';
SHOW VARIABLES LIKE 'collation%';
-- Criação correta da base de dados
CREATE DATABASE mydb
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
-- Tabela com a codificação correta
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
email VARCHAR(255)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Definições de ligação
SET NAMES 'utf8mb4';
SET CHARACTER_SET_CLIENT = 'utf8mb4';
SET CHARACTER_SET_CONNECTION = 'utf8mb4';
SET CHARACTER_SET_RESULTS = 'utf8mb4';

Codificação no PostgreSQL

-- Verificar a codificação
SHOW server_encoding;
SHOW client_encoding;
-- Criar base de dados com UTF-8
CREATE DATABASE mydb
ENCODING 'UTF8'
LC_COLLATE 'en_US.UTF-8'
LC_CTYPE 'en_US.UTF-8';
-- Definir a codificação do cliente
SET client_encoding TO 'UTF8';

Recuperar Dados Corrompidos

MySQL: Recuperar cp1251 a partir de Mojibake em UTF-8

Quando texto em cirílico foi armazenado com a codificação errada, o padrão «Привет» torna-se «Ð¿Ñ€Ð¸Ð²ÐµÑ‚»:

-- Diagnóstico: verificar o aspeto dos dados
SELECT
id,
text_column,
HEX(text_column) as hex_value
FROM broken_table
LIMIT 10;
-- Consulta de recuperação
SELECT
id,
CAST(
CONVERT(
CAST(CONVERT(text_column USING cp1251) AS BINARY)
USING utf8
)
AS CHAR CHARACTER SET cp1251
) COLLATE cp1251_general_ci AS fixed_text
FROM broken_table
WHERE text_column LIKE '%Ð%'; -- Padrão que indica mojibake
-- Atualizar dados corrompidos
UPDATE broken_table
SET text_column = CAST(
CONVERT(
CAST(CONVERT(text_column USING cp1251) AS BINARY)
USING utf8
)
AS CHAR CHARACTER SET cp1251
) COLLATE cp1251_general_ci
WHERE text_column REGEXP '^[Ð-ß]';

Compreender o Processo de Recuperação

A cadeia de conversão funciona porque:

  1. CONVERT(text_column USING cp1251) - Interpreta bytes UTF-8 como cp1251
  2. CAST(... AS BINARY) - Obtém os bytes em bruto
  3. CONVERT(... USING utf8) - Reinterpreta os bytes como UTF-8
  4. O cast final restaura para o charset de destino

PostgreSQL: Conversão de Codificação

-- Converter a codificação da coluna
UPDATE broken_table
SET text_column = convert_from(
convert_to(text_column, 'WIN1251'),
'UTF8'
)
WHERE text_column ~ '^[А-Яа-я]';
-- Ou usando bytea como intermédio
UPDATE broken_table
SET text_column = convert_from(
text_column::bytea,
'UTF8'
);

Tratamento de Codificação em PHP

Deteção e Conversão

<?php
// Detetar a codificação
function detectEncoding(string $text): string
{
$encodings = ['UTF-8', 'Windows-1251', 'ISO-8859-1', 'KOI8-R'];
foreach ($encodings as $encoding) {
if (mb_check_encoding($text, $encoding)) {
// Verificar por conversão de ida e volta
$converted = mb_convert_encoding($text, 'UTF-8', $encoding);
$back = mb_convert_encoding($converted, $encoding, 'UTF-8');
if ($back === $text) {
return $encoding;
}
}
}
return 'unknown';
}
// Converter para UTF-8
function toUtf8(string $text, ?string $fromEncoding = null): string
{
if ($fromEncoding === null) {
$fromEncoding = mb_detect_encoding($text, ['UTF-8', 'Windows-1251', 'ISO-8859-1'], true);
}
if ($fromEncoding === false || $fromEncoding === 'UTF-8') {
return $text;
}
return mb_convert_encoding($text, 'UTF-8', $fromEncoding);
}
// Corrigir UTF-8 com dupla codificação
function fixDoubleEncoding(string $text): string
{
// Verificar se parece UTF-8 com dupla codificação
if (preg_match('/[\xC0-\xDF][\x80-\xBF]/', $text)) {
$fixed = mb_convert_encoding($text, 'Windows-1251', 'UTF-8');
if (mb_check_encoding($fixed, 'UTF-8')) {
return $fixed;
}
}
return $text;
}
?>

Ligação à Base de Dados

<?php
// PDO com UTF-8
$pdo = new PDO(
'mysql:host=localhost;dbname=mydb;charset=utf8mb4',
$username,
$password,
[
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci",
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
]
);
// MySQLi com UTF-8
$mysqli = new mysqli('localhost', $username, $password, 'mydb');
$mysqli->set_charset('utf8mb4');
// Verificar o charset da ligação
if ($mysqli->character_set_name() !== 'utf8mb4') {
throw new RuntimeException('Failed to set UTF-8 encoding');
}
?>

Cabeçalhos HTTP e HTML

<?php
// Definir a codificação da resposta
header('Content-Type: text/html; charset=UTF-8');
// Para respostas JSON
header('Content-Type: application/json; charset=UTF-8');
echo json_encode($data, JSON_UNESCAPED_UNICODE);
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>

Tratamento de Codificação em Python

# Leitura de ficheiros com codificação
def read_file_safely(path: str) -> str:
encodings = ['utf-8', 'cp1251', 'iso-8859-1', 'koi8-r']
for encoding in encodings:
try:
with open(path, 'r', encoding=encoding) as f:
content = f.read()
# Verificar voltando a codificar
content.encode(encoding)
return content
except (UnicodeDecodeError, UnicodeEncodeError):
continue
raise ValueError(f"Could not decode {path} with any known encoding")
# Converter codificações
def convert_to_utf8(text: bytes, source_encoding: str = None) -> str:
if source_encoding:
return text.decode(source_encoding)
# Tentar deteção
import chardet
detected = chardet.detect(text)
return text.decode(detected['encoding'] or 'utf-8')
# Corrigir mojibake
def fix_mojibake(text: str) -> str:
try:
# Padrão comum: UTF-8 interpretado como cp1251
fixed = text.encode('cp1251').decode('utf-8')
return fixed
except (UnicodeDecodeError, UnicodeEncodeError):
return text

Codificação em JavaScript/Node.js

const iconv = require('iconv-lite');
// Converter o buffer para UTF-8
function toUtf8(buffer, encoding = 'win1251') {
return iconv.decode(buffer, encoding);
}
// Converter string para uma codificação diferente
function convertEncoding(text, from, to) {
const buffer = iconv.encode(text, from);
return iconv.decode(buffer, to);
}
// Leitura de ficheiro com codificação específica
const fs = require('fs');
function readFileWithEncoding(path, encoding = 'utf-8') {
const buffer = fs.readFileSync(path);
return iconv.decode(buffer, encoding);
}
// Middleware do Express.js para UTF-8
app.use((req, res, next) => {
res.setHeader('Content-Type', 'application/json; charset=utf-8');
next();
});

Ferramentas de Linha de Comandos

iconv

# Converter a codificação do ficheiro
iconv -f CP1251 -t UTF-8 input.txt > output.txt
# Converter com transliteração para caracteres não mapeáveis
iconv -f CP1251 -t UTF-8//TRANSLIT input.txt > output.txt
# Verificar a codificação do ficheiro
file -bi document.txt
# Saída: text/plain; charset=utf-8
# Converter ficheiros em lote
for f in *.txt; do
iconv -f CP1251 -t UTF-8 "$f" > "${f%.txt}_utf8.txt"
done

Linha de Comandos do MySQL

# Importar com codificação
mysql --default-character-set=utf8mb4 -u user -p database < dump.sql
# Exportar com codificação
mysqldump --default-character-set=utf8mb4 database > dump.sql

Boas Práticas de Prevenção

Usar Sempre UTF-8

# Base de dados: UTF-8
# Ficheiros: UTF-8 com BOM para compatibilidade com Windows
# HTTP: Content-Type com charset
# HTML: <meta charset="UTF-8">
# API: JSON com UTF-8

Validar Input

<?php
function validateUtf8Input(string $input): string
{
if (!mb_check_encoding($input, 'UTF-8')) {
// Tentar corrigir ou rejeitar
$fixed = mb_convert_encoding($input, 'UTF-8', 'auto');
if (!mb_check_encoding($fixed, 'UTF-8')) {
throw new InvalidArgumentException('Invalid UTF-8 input');
}
return $fixed;
}
return $input;
}
?>

Principais Conclusões

  1. Por defeito, UTF-8: Use utf8mb4 no MySQL, UTF-8 em todo o resto
  2. Defina a codificação explicitamente: Nunca assuma a codificação por defeito
  3. Faça corresponder cliente e servidor: A ligação à base de dados tem de corresponder à codificação da base de dados
  4. Valide o input: Verifique a codificação antes de processar
  5. Teste com dados reais: Inclua caracteres internacionais nos dados de teste
  6. Documente a codificação: Indique a codificação esperada em APIs e formatos de ficheiro

A codificação de caracteres é um problema resolvido quando é tratada de forma consistente — a complexidade surge ao lidar com sistemas legados e dados corrompidos. Domine estas técnicas de recuperação e poupará inúmeras horas a depurar problemas de codificação.

 
 
 
Языки
Темы
Copyright © 1999 — 2026
ZK Interactive