È valido UTF-8 modificato?


9

UTF-8 è un modo relativamente semplice per codificare i punti di codice Unicode in un formato a larghezza variabile in modo tale da non confondere facilmente il codice che non è a conoscenza di Unicode.

Panoramica UTF-8

  • I byte nell'intervallo 1-0x7F, inclusi, sono normalmente validi
  • I byte con il modello di bit 10XX XXXXsono considerati byte di continuazione, con i sei bit meno significativi utilizzati per codificare parte di un punto di codice. Questi non devono apparire a meno che non siano previsti da un byte precedente.
  • I byte con il modello 110X XXXXprevedono in seguito un byte di continuazione
  • I byte con il modello 1110 XXXXprevedono in seguito due byte di continuazione
  • I byte con il modello 1111 0XXXprevedono in seguito tre byte di continuazione
  • Tutti gli altri byte non sono validi e non dovrebbero apparire in nessun punto di un flusso UTF-8. I cluster a 5, 6 e 7 byte sono possibili in teoria, ma non saranno consentiti ai fini di questa sfida.

Codifiche troppo lunghe

UTF-8 richiede inoltre che un punto di codice sia rappresentato con il numero minimo di byte. Qualsiasi sequenza di byte che potrebbe essere rappresentata con meno byte non è valida. L'UTF-8 modificato aggiunge un'eccezione a questo per i caratteri null (U + 0000), che dovrebbero essere rappresentati come C0 80(rappresentazione esadecimale)) e non consente invece che i byte null vengano visualizzati in qualsiasi punto dello stream. (Questo lo rende compatibile con stringhe con terminazione null)

Sfida

Devi creare un programma che, quando viene data una stringa di byte, determinerà se quella stringa rappresenta UTF-8 modificato valido e restituirà un valore di verità se valido e un valore di falsa in caso contrario. Si noti che è necessario verificare la presenza di codifiche troppo lunghe e byte null (poiché si tratta di UTF-8 modificato). Non è necessario decodificare i valori UTF-8.

Esempi

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')

Regole

  • Si applicano regole standard e scappatoie
  • L'input e l'output possono essere in qualsiasi formato conveniente purché tutti i valori nell'intervallo di byte senza segno (0-255) possano essere letti.
    • Potrebbe essere necessario utilizzare un array o un file anziché una stringa con terminazione null. Devi essere in grado di leggere byte null.
  • Vince il codice più corto!
  • Si noti che l'uso di builtin per decodificare l'UTF-8 non è garantito conforme ai requisiti indicati qui. Potrebbe essere necessario aggirarlo e creare casi speciali.

EDIT: aggiunto il bonus per non usare i builtin che decodificano UTF-8

EDIT2: bonus rimosso poiché solo la risposta Rust è qualificata ed è difficile da definire.


Ho aspettato questo.
Adám,

È possibile che si desideri aggiungere un caso di test con un byte non valido nell'intervallo 0xF8-0xFF.
Arnauld,

2
Sembra che siano ammessi surrogati (0xD800 - 0xDFFF) e punti di codice oltre 0x10FFFF, contrariamente alle "moderne" specifiche UTF-8. Penso che questo dovrebbe essere chiarito, idealmente con casi di test aggiuntivi.
nwellnhof,

ulteriori esempi sarebbero utili
don luminoso

"I byte nell'intervallo 0-0x7F, inclusi, sono normalmente validi" dovrebbe essere compreso tra 1 e 0x7f?
don luminoso

Risposte:


2

Elisir , 69 byte

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

Provalo online!

Utilizza la funzione di convalida della stringa integrata. Accetta input come binario elisir.


1

APL (Dyalog Unicode) , 41 39 byte SBCS

Funzione prefisso tacito anonimo. Accetta una stringa Unicode come argomento in cui i punti di codice dei caratteri rappresentano i byte di input.

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

Provalo online!

'À\x80'⎕R⎕AR eplace C0 80s con le lettere maiuscole A lphabet

{... } applica la seguente funzione anonima, in cui l'argomento è :

0:: se si verifica un errore:

  0 restituisce zero

 provare:

  ⎕UCS⍵ converti la stringa in punti di codice

  'UTF-8'⎕UCS⍣2 interpretare come byte UTF-8 e convertire il testo risultante in byte

  ⌊/ byte più basso (zero se è presente un byte null, positivo in caso contrario, "infinito" se stringa vuota)

  × segno (zero se presente byte null, uno in caso contrario)


Questo ritorno non sarebbe vero D9 C0 80 84 C0 80 10?
Neil,

@Neil Lo fa davvero. È sbagliato perché la rimozione C0 80rende i byte non correlati adiacenti in un modo valido, sebbene non siano validi se separati? Modifica: aggiornato per risolvere il problema senza costi di byte.
Adám

alcuni dei personaggi appaiono sul mio schermo come rettangoli o scatole, è normale? sono in Firefox su Linux. APL è un linguaggio molto interessante.
don luminoso

@donbright Nella mia esperienza, i personaggi APL vengono sempre visualizzati correttamente, anche se a volte in modo meno che bello, quindi quelle scatole sono probabilmente solo Quad di cui dovrebbero esserne quattro nel codice principale. Dovrebbe essere visualizzato in questo modo . E sì, APL è fantastico e molto divertente. Puoi anche impararlo facilmente e rapidamente - vieni nel frutteto APL .
Adám,

si sono quad. Grazie.
don luminoso

0

Python 2 , 104 102 byte

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

Provalo online!

Uscite tramite codice di uscita


0

Ruggine - 191 byte 313 byte

Per commento sotto l'originale non ha funzionato correttamente. Versione nuova e migliorata. Non vengono utilizzate librerie, perché The Mighty Rust non ha bisogno di te e delle tue librerie. Questo codice utilizza la corrispondenza dei modelli con una macchina a stati. Strappando spudoratamente la specifica UTF8 , dopo averla trovata tramite riferimento e discussione di Jon Skeet , possiamo copiare la specifica quasi carattere per personaggio in un blocco di corrispondenze ruggine. Alla fine, aggiungiamo il requisito Mutf8 speciale di Beefster per C0 80 da considerare valido. Ungolfed:

/* 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;

provalo nel parco giochi ruggine


Puntelli per farlo manualmente, ma penso che il tuo controllo troppo lungo sia errato.
Beefster,

La tua sfida, caro signore, mi provoca all'imitazione, e concludo questa lettera sfidandoti, a mia volta, a fissare un uomo che esporrà la tua domanda in modo più schietto ( bit.ly/2T8tXhO )
don bright
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.