El objetivo es crear un convertidor totalmente compatible entre las codificaciones Unicode oficiales tal como se indica en las preguntas frecuentes de UTF . Dado que esto se centra en Unicode, aceptaré la respuesta con el recuento de bytes más bajo utilizando la mejor de las codificaciones posibles (que probablemente será UTF-8, a menos que tal vez la programes en APL). Pido disculpas por la larga publicación, pero gran parte explica las codificaciones a las que también se puede acceder en la especificación oficial (pdf, sección 3.9 D90 - D92) , o Wikipedia .
Especificaciones
Si en algún momento su idioma de elección no puede cumplir exactamente con un requisito, sustitúyalo por algo que mantenga el espíritu de las reglas dadas. P.ej. no todos los idiomas tienen arrays, funciones, etc. incorporados
No usar bibliotecas de cadenas / funciones, ni codificar bibliotecas / funciones. El objetivo de este código de golf es implementar el convertidor utilizando la manipulación bit / byte. Sin embargo, se permite el uso de cadenas en su capacidad como una matriz de caracteres o bytes. Ah, y tampoco hay llamadas del sistema operativo que realicen la conversión.
El convertidor es una función que tomará tres parámetros: una matriz de bytes que representa la cadena de entrada codificada y las codificaciones de "entrada" y "salida" representadas como números. Arbitrariamente asignaremos
UTF-8, UTF-16, UTF-16BE, UTF-16LE, UTF-32, UTF-32BE, and UTF32LE
números del 0 al 6 en ese orden. No es necesario verificar si el número es< 0
o> 6
, asumiremos que estos parámetros son correctos. El convertidor devolverá una matriz de bytes válida en la codificación de salida deseada.Usaremos el carácter nulo (
U+0000
) como un terminador de cadena. Cualquier cosa después de esto no importa. Asumiremos que la matriz de entrada tiene el carácter nulo en alguna parte, por lo que no necesita hacer una verificación de límites.Según las preguntas frecuentes , si la matriz de bytes de entrada no es válida para su codificación declarada, debemos señalar un error. Haremos esto de una de las siguientes maneras: bloquear el programa, lanzar una excepción, devolver nulo o devolver una matriz cuyos primeros cuatro bytes son todos 0 (para que pueda reconocerse como
U+0000
en cada codificación).
Las codificaciones
Deben seguirse las especificaciones oficiales, pero Wikipedia proporciona una buena (y hasta donde creo correcta) explicación de las codificaciones, y las resumiré aquí para completarlas. Tenga en cuenta que UTF-16 y UTF-32 tienen variantes para endianness .
UTF-32, UTF-32LE, UTF-32BE
La codificación más simple, cada punto de código simplemente se codifica en 4 bytes igual a su valor numérico. LE / BE representa endianness (little endian / big endian).
UTF-16, UTF-16LE, UTF-16BE
Los puntos de código de U+0000 - U+FFFF
se codifican en 2 bytes iguales a su valor numérico. Los valores más grandes se codifican utilizando un par de sustitutos que son valores reservados U+D800 - U+DFFF
. Entonces, para codificar puntos mayores que U+FFFF
, se puede usar el siguiente algoritmo (copiado descaradamente de Wikipedia ):
- 0x010000 se resta del punto de código, dejando un número de 20 bits en el rango 0..0x0FFFFF.
- Los primeros diez bits (un número en el rango 0..0x03FF) se agregan a 0xD800 para dar la primera unidad de código o sustituto principal, que estará en el rango 0xD800..0xDBFF [...].
- Los diez bits bajos (también en el rango 0..0x03FF) se agregan a 0xDC00 para dar la segunda unidad de código o sustituto de camino, que estará en el rango 0xDC00..0xDFFF [...].
UTF-8
Los puntos de código de U+0000 - U+007F
se codifican como 1 byte igual a su valor numérico. De U+0080 - U+07FF
ellos se codifican como 110xxxxx 10xxxxxx
, U+0800 - U+FFFF
es decir 1110xxxx 10xxxxxx 10xxxxxx
, los valores más altos son 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
. Los x
's son los bits del valor numérico del punto de código.
BOM
La marca de orden de bytes (BOM, U+FEFF
) se usa como el primer punto de código para indicar endianness. Siguiendo las pautas de preguntas frecuentes sobre las listas de materiales , la lista de materiales se utilizará de la siguiente manera: porque UTF-8, UTF-16 and UTF-32
es opcional. Si la lista de materiales está ausente en UTF-16
o UTF-32
, se supone que es big endian. La lista de materiales no debe aparecer en UTF-16LE, UTF-16BE, UTF-32LE and UTF-32BE
.
Errores comunes que causan UTF inválido
Varias cosas pueden hacer que una secuencia de bytes sea UTF no válida.
- UTF-8 y UTF-32: codificación directa de puntos de código sustituto (
U+D800 - U+DFFF
) o puntos de código mayores queU+10FFFF
. - UTF-8: muchas secuencias de bytes no válidas.
- UTF-16: sustitutos no emparejados o mal emparejados.
- BOM: debe usarse como se especifica en la sección de codificación. Tenga en cuenta que al generar
UTF-16
oUTF-32
(no se especifica endianness inherente) puede elegir, pero con little endian, debe incluir la lista de materiales.
Tenga en cuenta que los puntos de código no asignados y sin caracteres (ambos distintos de los sustitutos) deben tratarse como caracteres normales.
''⎕R''⍠'InEnc' 'UTF16BE' 'OutEnc' 'UTF8-BOM'
.Respuestas:
C ++, (UTF-8) 971 bytes
El siguiente programa legible puede condensarse en el formulario anterior filtrándolo a través del siguiente comando Perl:
El comando anterior
#include
líneas alrededor de las líneasCódigo legible
La función a llamar es
t()
, con las codificaciones de entrada y salida pasadas en las variables globalesi
yo
respectivamente, yp
apuntando a los bytes de entrada, que deben estar terminados en nulo.q
apunta al búfer de salida, que se sobrescribirá, y debe ser lo suficientemente grande para el resultado; no hay ningún intento de evitar el desbordamiento del búfer.Espero que los comentarios del código sean suficientemente explicativos: pregunte a continuación si uno de ellos es demasiado críptico (¡pero haga un esfuerzo primero!).
Recopilé un conjunto de pruebas sustancial mientras desarrollaba esta respuesta; Lo incluyo a continuación en beneficio de otros participantes y para documentar mi interpretación de los requisitos:
Funciones de prueba
Banco de pruebas
fuente
Python - 1367 caracteres UTF-8
¡Bien! Esta fue una pregunta extremadamente difícil debido a la gran cantidad de trabajo que llevó comprender e implementar todas las especificaciones, pero creo que tengo una implementación correcta.
convert
es la función que toma el objeto de datos 'bytes', la ID de entrada y la ID de salida. Parece funcionar, aunque Python parece tener un uso ligeramente roto de las listas de materiales cuando no se especifica en la codificación, por lo que usar la codificación incorporada de Python para probar los modos 1 y 4 no funcionará.Dato curioso : el tamaño también es 555 16 o 10101010101 2 .
773 caracteres para decodificar, 452 para codificar, 59 para verificación y 83 para partes misceláneas.
fuente
Python 3, 1138 bytes (UTF-8)
Resulta que 14 horas de viaje internacional son fantásticas. oportunidad para terminar un desafío de golf ...
La función de conversión es
C()
. Esta llamadasu()
,v()
yw()
para decodificar, yU()
,V()
yW()
para codificar, UTF-8, -16 y -32, respectivamente. Ninguno de los codificadores generará una lista de materiales, pero todos los decodificadores manejarán correctamente uno. Las condiciones de error dan como resultado una excepción (generalmente unaZeroDivisionError
cortesía de la función "morir de repente"E()
).fuente