Ist es gültig modifiziert UTF-8?

9

UTF-8 ist eine relativ einfache Methode zum Codieren von Unicode-Codepunkten in einem Format mit variabler Breite, sodass Code, der nicht Unicode-fähig ist, nicht leicht verwechselt werden kann.

UTF-8 Übersicht

  • Bytes im Bereich von 1-0x7F einschließlich sind normalerweise gültig
  • Bytes mit dem Bitmuster 10XX XXXXwerden als Fortsetzungsbytes betrachtet, wobei die sechs niedrigstwertigen Bits zum Codieren eines Teils eines Codepunkts verwendet werden. Diese dürfen nur angezeigt werden, wenn sie von einem vorhergehenden Byte erwartet werden.
  • Bytes mit dem Muster 110X XXXXerwarten danach ein Fortsetzungsbyte
  • Bytes mit dem Muster 1110 XXXXerwarten danach zwei Fortsetzungsbytes
  • Bytes mit dem Muster 1111 0XXXerwarten danach drei Fortsetzungsbytes
  • Alle anderen Bytes sind ungültig und sollten nirgendwo in einem UTF-8-Stream erscheinen. 5-, 6- und 7-Byte-Cluster sind theoretisch möglich, werden jedoch für die Zwecke dieser Herausforderung nicht zugelassen.

Überlange Codierungen

UTF-8 erfordert auch, dass ein Codepunkt mit der Mindestanzahl von Bytes dargestellt wird. Jede Bytesequenz, die mit weniger Bytes dargestellt werden könnte, ist ungültig. Modifiziertes UTF-8 fügt eine Ausnahme für Nullzeichen (U + 0000) hinzu, die als C0 80(Hex-Darstellung) dargestellt werden sollten, und verhindert stattdessen, dass Null-Bytes irgendwo im Stream angezeigt werden. (Dies macht es kompatibel mit nullterminierten Zeichenfolgen)

Herausforderung

Sie müssen ein Programm erstellen, das bei Angabe einer Byte-Zeichenfolge feststellt, ob diese Zeichenfolge ein gültiges modifiziertes UTF-8 darstellt, und ansonsten einen Wahrheitswert und einen Falschwert zurückgibt. Beachten Sie, dass Sie nach überlangen Codierungen und Null-Bytes suchen müssen (da dies Modified UTF-8 ist). Sie müssen die UTF-8-Werte nicht dekodieren.

Beispiele

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

Regeln

  • Es gelten Standardregeln und Lücken
  • Die Ein- und Ausgabe kann in jedem geeigneten Format erfolgen, solange alle Werte im vorzeichenlosen Bytebereich (0-255) eingelesen werden können.
    • Möglicherweise müssen Sie ein Array oder eine Datei anstelle einer nullterminierten Zeichenfolge verwenden. Sie müssen in der Lage sein, Null-Bytes zu lesen.
  • Der kürzeste Code gewinnt!
  • Beachten Sie, dass die Verwendung von integrierten Funktionen zum Decodieren des UTF-8 nicht den hier angegebenen Anforderungen entspricht. Möglicherweise müssen Sie es umgehen und Sonderfälle erstellen.

BEARBEITEN: Zusätzlicher Bonus für die Nichtverwendung von integrierten Funktionen, die UTF-8 dekodieren

EDIT2: Bonus entfernt, da nur die Rust-Antwort qualifiziert ist und es umständlich zu definieren ist.

Beefster
quelle
Ich habe auf diesen gewartet.
Adám
Möglicherweise möchten Sie einen Testfall mit einem ungültigen Byte im Bereich 0xF8-0xFF hinzufügen.
Arnauld
2
Es scheint, dass Ersatzzeichen (0xD800 - 0xDFFF) und Codepunkte jenseits von 0x10FFFF entgegen der "modernen" UTF-8-Spezifikation zulässig sind. Ich denke, dies sollte geklärt werden, idealerweise mit zusätzlichen Testfällen.
Nwellnhof
Weitere Beispiele wären hilfreich
Don Bright
"Bytes im Bereich von 0-0x7F einschließlich sind normalerweise gültig" soll das 1 bis 0x7f sein?
Don Bright

Antworten:

2

Elixier , 69 Bytes

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

Probieren Sie es online aus!

Verwendet die integrierte Zeichenfolgenüberprüfungsfunktion. Nimmt die Eingabe als Elixir-Binärdatei auf.

Kirill L.
quelle
1

APL (Dyalog Unicode) , 41 39 Byte SBCS

Anonyme stillschweigende Präfixfunktion. Nimmt eine Unicode-Zeichenfolge als Argument, wobei die Codepunkte der Zeichen die Eingabebytes darstellen.

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

Probieren Sie es online aus!

'À\x80'⎕R⎕AR ePlace C0 80s mit dem Großbuchstaben A lphabet

{} Wenden Sie die folgende anonyme Funktion an, wobei das Argument lautet :

0:: Wenn ein Fehler auftritt:

  0 Null zurückgeben

 Versuchen:

  ⎕UCS⍵ Konvertieren Sie die Zeichenfolge in Codepunkte

  'UTF-8'⎕UCS⍣2 als UTF-8-Bytes interpretieren und resultierenden Text zurück in Bytes konvertieren

  ⌊/ niedrigstes Byte (Null, wenn ein Null-Byte vorhanden ist, positiv, wenn nicht, "unendlich", wenn leere Zeichenfolge)

  × Vorzeichen (Null, wenn Null-Byte vorhanden ist, Eins, wenn nicht)

Adam
quelle
Würde das nicht wahrheitsgemäß zurückkehren D9 C0 80 84 C0 80 10?
Neil
@ Neil Es tut in der Tat. Ist das falsch, weil durch das Entfernen C0 80nicht verwandte Bytes auf eine gültige Weise benachbart werden, obwohl sie ungültig sind, wenn sie getrennt sind? Bearbeiten: Aktualisiert, um dies ohne Bytekosten zu beheben.
Adám
Einige der Zeichen erscheinen auf meinem Bildschirm nur als Rechtecke oder Kästchen. Ist das normal? Ich bin in Firefox unter Linux. APL ist eine sehr interessante Sprache.
Don Bright
@donbright Nach meiner Erfahrung werden APL-Zeichen immer korrekt gerendert, auch wenn sie manchmal weniger schön sind. Daher sind diese Felder wahrscheinlich nur Quads, von denen der Hauptcode vier enthalten sollte. Es sollte wie machen diese . Und ja, APL ist unglaublich und macht viel Spaß. Sie können es auch einfach und schnell lernen - kommen Sie einfach in den APL-Obstgarten .
Adám
Ja, sie sind Quads. Vielen Dank.
Don Bright
0

Rost - 191 Bytes 313 Bytes

Per Kommentar unten Original hat nicht richtig funktioniert. Neue und verbesserte Version. Es werden keine Bibliotheken verwendet, da The Mighty Rust Sie und Ihre Bibliotheken nicht benötigt. Dieser Code verwendet den Mustervergleich mit einer Zustandsmaschine. Indem wir die UTF8-Spezifikation schamlos abreißen , nachdem wir sie durch Referenz und Diskussion von Jon Skeet gefunden haben , können wir die Spezifikation fast zeichenweise in einen Rost-Match-Muster-Übereinstimmungsblock kopieren. Am Ende fügen wir Beefsters spezielle Mutf8-Anforderung hinzu, dass C0 80 als gültig gilt. 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;

Probieren Sie es auf dem Rostspielplatz

nicht hell
quelle
Requisiten für die manuelle Ausführung, aber ich denke, Ihre überlange Prüfung ist falsch.
Beefster
Ihre Herausforderung, sehr geehrter Herr, provoziert mich zur Nachahmung, und ich schließe diesen Brief, indem ich Sie wiederum auffordere , sich auf einen Mann zu konzentrieren, der Ihre Frage unverblümt aufdeckt ( bit.ly/2T8tXhO )
don bright