O objetivo é criar um conversor totalmente compatível entre as codificações Unicode oficiais, conforme indicado nas Perguntas frequentes da UTF . Dado que isso é centrado no Unicode, aceitarei a resposta com a menor contagem de bytes, usando o melhor possível das codificações envolvidas (que provavelmente será UTF-8, a menos que você possa programá-lo no APL). Peço desculpas pelo longo post, mas muito disso explica as codificações que também podem ser acessadas na especificação oficial (pdf, seção 3.9 D90 - D92) , ou Wikipedia .
Especificações
Se, a qualquer momento, o idioma de sua escolha não puder atender exatamente a um requisito, substitua-o por algo que atenda ao espírito das regras fornecidas. Por exemplo. nem todo idioma possui matrizes, funções etc. integradas
Não é possível usar bibliotecas / funções de cadeias ou bibliotecas / funções de codificação. O objetivo desse código de golfe é implementar o conversor usando manipulação de bits / bytes. No entanto, é possível usar as próprias strings em sua capacidade como uma matriz de caracteres ou bytes. Ah, e nenhuma chamada do SO que realize a conversão também.
O conversor é uma função que aceita três parâmetros: uma matriz de bytes que representa a cadeia de entrada codificada e as codificações "entrada" e "saída" representadas como números. Arbitrariamente, atribuiremos
UTF-8, UTF-16, UTF-16BE, UTF-16LE, UTF-32, UTF-32BE, and UTF32LE
números de 0 a 6 nessa ordem. Não há necessidade de verificar se o número é< 0
ou> 6
, assumiremos que esses parâmetros estão corretos. O conversor retornará uma matriz de bytes válida na codificação de saída desejada.Usaremos o caractere nulo (
U+0000
) como um terminador de string. Qualquer coisa depois disso não importa. Vamos supor que a matriz de entrada tenha o caractere nulo em algum lugar, para que você não precise fazer uma verificação de limites.Conforme a FAQ , se a matriz de bytes de entrada for inválida para sua codificação declarada, devemos sinalizar um erro. Faremos isso de uma das seguintes maneiras: travar o programa, lançar uma exceção, retornar nulo ou retornar uma matriz cujos quatro primeiros bytes sejam todos 0 (para que possa ser reconhecido como
U+0000
em todas as codificações).
As codificações
As especificações oficiais devem ser seguidas, mas a Wikipedia fornece uma explicação boa (e até onde eu acredito correta) das codificações, e eu as resumirei aqui para garantir a integridade. Observe que UTF-16 e UTF-32 têm variantes para endianness .
UTF-32, UTF-32LE, UTF-32BE
A codificação mais simples, cada ponto de código é simplesmente codificado em 4 bytes igual ao seu valor numérico. LE / BE representa endianness (little endian / big endian).
UTF-16, UTF-16LE, UTF-16BE
Os pontos de código de U+0000 - U+FFFF
são codificados em 2 bytes iguais ao seu valor numérico. Valores maiores são codificados usando um par de substitutos dos quais são valores reservados U+D800 - U+DFFF
. Portanto, para codificar pontos maiores que U+FFFF
, o seguinte algoritmo pode ser usado (copiado descaradamente da Wikipedia ):
- 0x010000 é subtraído do ponto de código, deixando um número de 20 bits no intervalo 0..0x0FFFFF.
- Os dez principais bits (um número no intervalo 0..0x03FF) são adicionados ao 0xD800 para fornecer a primeira unidade de código ou substituto principal, que estará no intervalo 0xD800..0xDBFF [...].
- Os dez bits baixos (também no intervalo 0..0x03FF) são adicionados a 0xDC00 para fornecer a segunda unidade de código ou substituto de trilha, que estará no intervalo 0xDC00..0xDFFF [...].
UTF-8
Os pontos de código de U+0000 - U+007F
são codificados como 1 byte igual ao seu valor numérico. Desde que U+0080 - U+07FF
eles são codificados como 110xxxxx 10xxxxxx
, U+0800 - U+FFFF
é 1110xxxx 10xxxxxx 10xxxxxx
, são os valores mais altos 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
. Os x
são os bits do valor numérico do ponto de código.
BOM
A marca de ordem de byte (BOM U+FEFF
) é usada como o primeiro ponto de código para indicar endianness. Seguindo as diretrizes de perguntas frequentes sobre listas técnicas , a lista técnica será usada da seguinte maneira: Por UTF-8, UTF-16 and UTF-32
ser opcional. Se a lista técnica estiver ausente em UTF-16
ou UTF-32
, será considerado grande endian. A lista técnica não deve aparecer UTF-16LE, UTF-16BE, UTF-32LE and UTF-32BE
.
Armadilhas comuns que causam UTF inválido
Várias coisas podem fazer com que uma sequência de bytes seja UTF inválida.
- UTF-8 e UTF-32: codificação direta de pontos de código substitutos (
U+D800 - U+DFFF
) ou pontos de código maiores queU+10FFFF
. - UTF-8: Muitas seqüências de bytes inválidas.
- UTF-16: Substitutos emparelhados ou emparelhados incorretamente.
- BOM: deve ser usado conforme especificado na seção de codificação. Observe que ao emitir
UTF-16
ouUTF-32
(nenhuma endianidade inerente especificada) você pode selecionar, mas com pouca endian, você deve incluir a BOM.
Observe que não-caracteres e pontos de código não atribuídos (ambos distintos dos substitutos) devem ser tratados como caracteres regulares.
''⎕R''⍠'InEnc' 'UTF16BE' 'OutEnc' 'UTF8-BOM'
,.Respostas:
C ++, (UTF-8) 971 bytes
O programa legível abaixo pode ser condensado na forma acima, filtrando-o através do seguinte comando Perl:
O comando acima
#include
linhas em torno das linhasCódigo legível
A função a ser chamada é
t()
, com as codificações de entrada e saída passadas nas variáveis globaisi
eo
, respectivamente, ep
apontando para os bytes de entrada, que devem ter terminação nula.q
aponta para o buffer de saída, que será substituído e deve ser grande o suficiente para o resultado - não há tentativa de evitar a saturação do buffer.Espero que os comentários do código sejam suficientemente explicativos - pergunte abaixo se um deles é muito enigmático (mas faça um esforço primeiro!).
Compilei uma suíte de testes substancial ao desenvolver esta resposta; Eu o incluo abaixo para o benefício de outros participantes e para documentar minha interpretação dos requisitos:
Funções de teste
Suíte de teste
fonte
Python - 1367 caracteres UTF-8
Bem! Essa foi uma pergunta extremamente difícil devido à enorme quantidade de trabalho necessário para entender e implementar todas as especificações, mas acho que tenho uma implementação correta.
convert
é a função que pega o objeto 'bytes' dos dados, o ID de entrada e o ID de saída. Parece funcionar - embora o python pareça ter um uso ligeiramente quebrado das BOMs quando não especificado na codificação, portanto, o uso da codificação interna do python para testar os modos 1 e 4 não funcionará.Curiosidade: o tamanho também é 555 16 ou 10101010101 2 .
773 caracteres para decodificação, 452 para codificação, 59 para verificação e 83 para peças diversas.
fonte
Python 3, 1138 bytes (UTF-8)
Acontece que 14 horas de viagens internacionais são uma oportunidade fantástica para terminar um desafio de golfe ...
A função de conversão é
C()
. Isto exigeu()
,v()
ew()
para decodificar, eU()
,V()
e,W()
para codificar, UTF-8, -16 e -32, respectivamente. Nenhum dos codificadores produzirá uma BOM, mas todos os decodificadores manipularão corretamente um. As condições de erro resultam em uma exceção (geralmente aZeroDivisionError
, cortesia da função "morrer repentinamente"E()
).fonte