L'objectif est de créer un convertisseur entièrement conforme entre les encodages Unicode officiels comme indiqué dans la FAQ UTF . Étant donné que cela est centré sur Unicode, j'accepterai la réponse avec le nombre d'octets le plus bas en utilisant le meilleur possible des codages impliqués (qui sera probablement UTF-8, à moins que vous ne le programmiez en APL). Je m'excuse pour le long post, mais une grande partie explique les encodages qui peuvent également être consultés dans les spécifications officielles (pdf, section 3.9 D90 - D92) , ou Wikipedia .
Caractéristiques
Si à tout moment votre langue de choix ne peut pas répondre exactement à une exigence, remplacez-la par quelque chose qui colle à l'esprit des règles données. Par exemple. tous les langages n'ont pas de tableaux, de fonctions, etc.
Pas d'utilisation de bibliothèques / fonctions de chaîne, ni d'encodage de bibliothèques / fonctions. Le but de ce code golf est d'implémenter le convertisseur en utilisant une manipulation bit / octet. Cependant, l'utilisation de chaînes elles-mêmes en tant que tableau de caractères ou d'octets est autorisée. Oh, et aucun appel OS qui effectue la conversion non plus.
Le convertisseur est une fonction qui prendra trois paramètres: un tableau d'octets représentant la chaîne d'entrée codée et les codages "d'entrée" et "de sortie" représentés sous forme de nombres. Arbitrairement, nous attribuerons des
UTF-8, UTF-16, UTF-16BE, UTF-16LE, UTF-32, UTF-32BE, and UTF32LE
nombres de 0 à 6 dans cet ordre. Il n'est pas nécessaire de vérifier si le nombre est< 0
ou> 6
, nous supposerons que ces paramètres sont corrects. Le convertisseur renverra un tableau d'octets valide dans le codage de sortie souhaité.Nous utiliserons le caractère nul (
U+0000
) comme terminateur de chaîne. Rien après cela n'a pas d'importance. Nous supposerons que le tableau d'entrée a le caractère nul quelque part, vous n'avez donc pas besoin de vérifier les limites.Selon la FAQ , si le tableau d'octets d'entrée n'est pas valide pour son encodage déclaré, nous devons signaler une erreur. Nous allons le faire de l'une des manières suivantes: planter le programme, lever une exception, retourner null ou retourner un tableau dont les quatre premiers octets sont tous à 0 (afin qu'il puisse être reconnu comme
U+0000
dans chaque encodage).
Les encodages
Les spécifications officielles doivent être suivies, mais Wikipédia fournit une bonne (et pour autant que je pense correcte) explication des encodages, et je les résumerai ici pour être complet. Notez que UTF-16 et UTF-32 ont des variantes pour l' endianité .
UTF-32, UTF-32LE, UTF-32BE
Le codage le plus simple, chaque point de code est simplement codé en 4 octets égal à sa valeur numérique. LE / BE représente l'endianité (petit endian / gros endian).
UTF-16, UTF-16LE, UTF-16BE
Les points de code de U+0000 - U+FFFF
sont codés sur 2 octets égaux à sa valeur numérique. Les valeurs plus grandes sont codées à l'aide d'une paire de substituts qui sont des valeurs réservées de U+D800 - U+DFFF
. Donc, pour encoder des points supérieurs à U+FFFF
, l'algorithme suivant peut être utilisé (copié sans vergogne à partir de Wikipedia ):
- 0x010000 est soustrait du point de code, laissant un nombre de 20 bits dans la plage 0..0x0FFFFF.
- Les dix premiers bits (un nombre dans la plage 0..0x03FF) sont ajoutés à 0xD800 pour donner la première unité de code ou substitut de tête, qui sera dans la plage 0xD800..0xDBFF [...].
- Les dix bits les plus faibles (également dans la plage 0..0x03FF) sont ajoutés à 0xDC00 pour donner la deuxième unité de code ou substitut de piste, qui sera dans la plage 0xDC00..0xDFFF [...].
UTF-8
Les points de code de U+0000 - U+007F
sont codés sur 1 octet égal à sa valeur numérique. De, U+0080 - U+07FF
ils sont codés comme 110xxxxx 10xxxxxx
, U+0800 - U+FFFF
est 1110xxxx 10xxxxxx 10xxxxxx
, les valeurs plus élevées sont 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
. Les x
'sont les bits de la valeur numérique du point de code.
Nomenclature
La marque d'ordre des octets (BOM, U+FEFF
) est utilisée comme premier point de code pour indiquer l'endianité. En suivant les directives de la FAQ sur les nomenclatures , la nomenclature sera utilisée comme suit: car UTF-8, UTF-16 and UTF-32
elle est facultative. Si la nomenclature est absente dans UTF-16
ou UTF-32
, elle est supposée être big endian. La nomenclature ne doit pas apparaître dans UTF-16LE, UTF-16BE, UTF-32LE and UTF-32BE
.
Pièges courants provoquant un UTF non valide
Diverses choses peuvent rendre une séquence d'octets non valide UTF.
- UTF-8 et UTF-32: encodage direct des points de code de substitution (
U+D800 - U+DFFF
) ou des points de code supérieurs àU+10FFFF
. - UTF-8: nombreuses séquences d'octets invalides.
- UTF-16: substituts non appariés ou mal appariés.
- BOM: Doit être utilisé comme spécifié dans la section de codage. Notez que lors de la sortie
UTF-16
ouUTF-32
(aucune endianité inhérente spécifiée) vous pouvez choisir, mais avec peu d'endian, vous devez inclure la nomenclature.
Notez que les non-caractères et les points de code non attribués (tous deux distincts des substituts) doivent être traités comme des caractères normaux.
''⎕R''⍠'InEnc' 'UTF16BE' 'OutEnc' 'UTF8-BOM'
.Réponses:
C ++, (UTF-8) 971 octets
Le programme lisible ci-dessous peut être condensé à la forme ci-dessus en le filtrant via la commande Perl suivante:
La commande ci-dessus
#include
lignes autour des lignesCode lisible
La fonction à appeler est
t()
, avec des encodages d'entrée et de sortie passés dans les variables globalesi
eto
respectivement, etp
pointant vers les octets d'entrée, qui doivent être terminés par des valeurs nulles.q
pointe vers le tampon de sortie, qui sera écrasé, et doit être suffisamment grand pour le résultat - il n'y a aucune tentative pour éviter un dépassement de tampon.J'espère que les commentaires du code sont suffisamment explicatifs - demandez ci-dessous si l'un d'eux est trop cryptique (mais faites d'abord un effort!).
J'ai compilé une suite de tests substantielle tout en développant cette réponse; Je l'inclus ci-dessous pour le bénéfice des autres participants et pour documenter mon interprétation des exigences:
Fonctions de test
Suite de tests
la source
Python - 1367 caractères UTF-8
Bien! C'était une question extrêmement difficile en raison de la quantité de travail qu'il a fallu pour comprendre et mettre en œuvre toutes les spécifications, mais je pense que j'ai une mise en œuvre correcte.
convert
est la fonction qui prend l'objet «octets» de données, l'ID d'entrée et l'ID de sortie. Cela semble fonctionner - bien que python semble avoir une utilisation légèrement cassée des nomenclatures lorsqu'il n'est pas spécifié dans l'encodage, donc utiliser l'encodage intégré de python pour tester les modes 1 et 4 ne fonctionnera pas.Fait amusant: la taille est également de 555 16 ou 10101010101 2 .
773 caractères pour le décodage, 452 pour le codage, 59 pour la vérification et 83 pour les pièces diverses.
la source
Python 3, 1138 octets (UTF-8)
Il s'avère donc que 14 heures de voyages internationaux sont une opportunité fantastique pour terminer un défi de golf ...
La fonction de conversion est
C()
. Cela demandeu()
,v()
etw()
à décoder, etU()
,V()
etW()
à coder, UTF-8, -16 et -32 respectivement. Aucun des encodeurs ne sortira une nomenclature, mais tous les décodeurs en géreront correctement un. Les conditions d'erreur entraînent une exception (généralement uneZeroDivisionError
, grâce à la fonction "mourir subitement"E()
).la source