Est-il valide UTF-8 modifié?

9

UTF-8 est un moyen relativement simple de coder les points de code Unicode dans un format à largeur variable de sorte qu'il ne confond pas facilement le code qui n'est pas compatible avec Unicode.

Présentation de l'UTF-8

  • Les octets compris entre 1 et 0 x 7 F, inclus, sont normalement valides
  • Les octets avec la configuration binaire 10XX XXXXsont considérés comme des octets de continuation, les six bits les moins significatifs étant utilisés pour coder une partie d'un point de code. Ceux-ci ne doivent apparaître que s'ils sont attendus par un octet précédent.
  • Les octets avec le modèle 110X XXXXattendent un octet de suite par la suite
  • Les octets avec le modèle 1110 XXXXattendent deux octets de suite par la suite
  • Les octets avec le modèle 1111 0XXXattendent trois octets de suite par la suite
  • Tous les autres octets ne sont pas valides et ne doivent apparaître nulle part dans un flux UTF-8. Les clusters de 5, 6 et 7 octets sont théoriquement possibles, mais ne seront pas autorisés aux fins de ce défi.

Encodages trop longs

UTF-8 exige également qu'un point de code soit représenté avec le nombre minimal d'octets. Toute séquence d'octets pouvant être représentée avec moins d'octets n'est pas valide. UTF-8 modifié ajoute une exception à cela pour les caractères nuls (U + 0000), qui devraient être représentés comme C0 80(représentation hexadécimale)), et interdit à la place les octets nuls à apparaître n'importe où dans le flux. (Cela le rend compatible avec les chaînes terminées par null)

Défi

Vous devez créer un programme qui, lorsqu'il recevra une chaîne d'octets, déterminera si cette chaîne représente un UTF-8 modifié valide et renverra une valeur véridique si elle est valide et une valeur falsifiée dans le cas contraire. Notez que vous devez vérifier les encodages trop longs et les octets nuls (car il s'agit de UTF-8 modifié). Vous n'avez pas besoin de décoder les valeurs UTF-8.

Exemples

41 42 43  ==> yes (all bytes are in the 0-0x7F range)
00 01 02  ==> no (there is a null byte in the stream)
80 7F 41  ==> no (there is a continuation byte without a starter byte)
D9 84 10  ==> yes (the correct number of continuation bytes follow a starter byte)
F0 81 82 41  ==> no (there are not enough continuation bytes after F0)
EF 8A A7 91  ==> no (too many continuation bytes)
E1 E1 01  ==> no (starter byte where a continuation byte is expected)
E0 80 87  ==> no (overlong encoding)
41 C0 80  ==> yes (null byte encoded with the only legal overlong encoding)
F8 42 43  ==> no (invalid byte 'F8')

Règles

  • Des règles et des lacunes standard s'appliquent
  • L'entrée et la sortie peuvent être dans n'importe quel format pratique tant que toutes les valeurs dans la plage d'octets non signés (0-255) peuvent être lues.
    • Vous devrez peut-être utiliser un tableau ou un fichier plutôt qu'une chaîne terminée par un caractère nul. Vous devez pouvoir lire des octets nuls.
  • Le code le plus court gagne!
  • Notez que l'utilisation de fonctions intégrées pour décoder l'UTF-8 n'est pas garantie de se conformer aux exigences données ici. Vous devrez peut-être contourner ce problème et créer des cas spéciaux.

EDIT: bonus supplémentaire pour ne pas utiliser de builtins qui décodent UTF-8

EDIT2: bonus supprimé car seule la réponse Rust est qualifiée et difficile à définir.

Beefster
la source
J'attendais celui-ci.
Adám
Vous souhaiterez peut-être ajouter un cas de test avec un octet non valide dans la plage 0xF8-0xFF.
Arnauld
2
Il semble que les substituts (0xD800 - 0xDFFF) et les points de code au-delà de 0x10FFFF soient autorisés, contrairement à la spécification "moderne" UTF-8. Je pense que cela devrait être clarifié, idéalement avec des cas de test supplémentaires.
nwellnhof
d'autres exemples seraient utiles
don bright
"Les octets dans la plage de 0-0x7F, inclus, sont normalement valides" est-ce censé être compris entre 1 et 0x7f?
don bright

Réponses:

2

Elixir , 69 octets

import String
&valid? replace replace(&1,<<0>>,"\xFF"),"\xC0\x80","0"

Essayez-le en ligne!

Utilise la fonction de validation de chaîne intégrée. Prend l'entrée en binaire Elixir.

Kirill L.
la source
1

APL (Dyalog Unicode) , 41 39 octets SBCS

Fonction de préfixe tacite anonyme. Prend une chaîne Unicode comme argument où les points de code des caractères représentent les octets d'entrée.

{0::0⋄×⌊/'UTF-8'UCS2UCS⍵}'À\x80'RA

Essayez-le en ligne!

'À\x80'⎕R⎕AR eplace C0 80s avec les majuscules A lphabet

{} Appliquez la fonction anonyme suivante, où l'argument est :

0:: en cas d'erreur:

  0 retourner zéro

 essayer:

  ⎕UCS⍵ convertir la chaîne en points de code

  'UTF-8'⎕UCS⍣2 interpréter comme des octets UTF-8 et convertir le texte résultant en octets

  ⌊/ octet le plus bas (zéro si un octet nul est présent, positif sinon, "infini" si chaîne vide)

  × signe (zéro si l'octet nul est présent, un sinon)

Adam
la source
Cela ne reviendrait-il pas à la vérité D9 C0 80 84 C0 80 10?
Neil
@Neil C'est vrai. Est-ce faux parce que la suppression C0 80rend les octets non liés adjacents d'une manière valide, bien qu'ils ne soient pas valides lorsqu'ils sont séparés? Edit: mis à jour pour corriger cela sans frais d'octet.
Adám
certains personnages apparaissent sur mon écran sous forme de rectangles ou de cases, est-ce normal? im dans firefox sur linux. APL est une langue très intéressante.
don bright
@donbright D'après mon expérience, les caractères APL s'affichent toujours correctement, même si parfois moins que magnifiquement, donc ces cases ne sont probablement que des Quads dont il devrait y en avoir quatre dans le code principal. Cela devrait être rendu comme ça . Et oui, APL est incroyable et très amusant. Vous pouvez également l'apprendre facilement et rapidement - venez simplement dans le verger APL .
Adám
oui ce sont des quads. Merci.
don bright
0

Python 2 , 104 102 octets

''.join(chr(int(c,16))for c in input().replace('00','-').replace('C0 80','0').split()).decode('utf-8')

Essayez-le en ligne!

Sorties via code de sortie

TFeld
la source
0

Rouille - 191 octets 313 octets

Par commentaire ci-dessous, l'original ne fonctionnait pas correctement. Version nouvelle et améliorée. Aucune bibliothèque n'est utilisée, car The Mighty Rust n'a pas besoin de vous et de vos bibliothèques. Ce code utilise une correspondance de modèle avec une machine d'état. En arrachant sans vergogne la spécification UTF8 , après l'avoir trouvée via une référence et une discussion par Jon Skeet , nous pouvons copier la spécification presque caractère pour caractère dans un bloc de correspondance de motif de correspondance de rouille. À la fin, nous ajoutons l'exigence spéciale Mutf8 de Beefster pour que le C0 80 soit considéré comme valide. Non golfé:

/* http://www.unicode.org/versions/corrigendum1.html
 Code Points        1st Byte    2nd Byte    3rd Byte    4th Byte
U+0000..U+007F      00..7F           
U+0080..U+07FF      C2..DF      80..BF           
U+0800..U+0FFF      E0          A0..BF      80..BF       
U+1000..U+FFFF      E1..EF      80..BF      80..BF       
U+10000..U+3FFFF    F0          90..BF      80..BF      80..BF
U+40000..U+FFFFF    F1..F3      80..BF      80..BF      80..BF
U+100000..U+10FFFF  F4          80..8F      80..BF      80..BF
*/

let m=|v:&Vec<u8>|v.iter().fold(0, |s, b| match (s, b) {
        (0, 0x01..=0x7F) => 0,
        (0, 0xc2..=0xdf) => 1,
        (0, 0xe0) => 2,
        (0, 0xe1..=0xef) => 4,
        (0, 0xf0) => 5,
        (0, 0xf1..=0xf3) => 6,
        (0, 0xf4) => 7,
        (1, 0x80..=0xbf) => 0,
        (2, 0xa0..=0xbf) => 1,
        (4, 0x80..=0xbf) => 1,
        (5, 0x90..=0xbf) => 4,
        (6, 0x80..=0xbf) => 4,
        (7, 0x80..=0x8f) => 4,
        (0, 0xc0) => 8, // beefster mutf8 null
        (8, 0x80) => 0, // beefster mutf8 null
        _ => -1,
    })==0;

essayez-le sur le terrain de jeu de la rouille

Don Bright
la source
Accessoires pour le faire manuellement, mais je pense que votre vérification trop longue est incorrecte.
Beefster
Votre défi, cher monsieur, me provoque à l'imitation, et je conclus cette lettre en vous mettant au défi, à mon tour, de vous fixer sur un homme qui exposera votre question de façon plus directe ( bit.ly/2T8tXhO )
don bright