Czy jest to poprawna modyfikacja UTF-8?

9

UTF-8 jest stosunkowo prostym sposobem kodowania punktów kodowych Unicode w formacie o zmiennej szerokości, dzięki czemu nie łatwo pomylić kodu, który nie jest świadomy Unicode.

Omówienie UTF-8

  • Bajty w zakresie 1-0x7F włącznie, zwykle są prawidłowe
  • Bajty ze wzorem bitowym 10XX XXXXsą uważane za bajty kontynuacyjne, przy czym sześć najmniej znaczących bitów jest używanych do kodowania części punktu kodowego. Nie mogą się pojawiać, chyba że oczekują ich poprzednie bajty.
  • Bajty ze wzorem 110X XXXXoczekują później jednego bajtu kontynuacji
  • Bajty ze wzorcem 1110 XXXXoczekują później dwóch bajtów kontynuacji
  • Bajty ze wzorcem 1111 0XXXoczekują później trzech bajtów kontynuacji
  • Wszystkie pozostałe bajty są nieprawidłowe i nie powinny pojawiać się nigdzie w strumieniu UTF-8. Teoretycznie klastry 5, 6 i 7 bajtów są możliwe, ale nie będą dozwolone na potrzeby tego wyzwania.

Zbyt długie kodowanie

UTF-8 wymaga również, aby kod był reprezentowany przez minimalną liczbę bajtów. Każda sekwencja bajtów, która może być reprezentowana przez mniej bajtów, jest niepoprawna. Zmodyfikowany UTF-8 dodaje jeden wyjątek dla znaków zerowych (U + 0000), które powinny być reprezentowane jako C0 80(reprezentacja szesnastkowa), i zamiast tego uniemożliwia pojawienie się pustych bajtów w dowolnym miejscu w strumieniu. (Dzięki temu jest kompatybilny z ciągami zakończonymi znakiem null)

Wyzwanie

Masz stworzyć program, który, gdy otrzyma ciąg bajtów, określi, czy ten ciąg reprezentuje prawidłową Zmodyfikowaną UTF-8 i zwróci prawdę, jeśli jest poprawna, lub wartość fałszowania w przeciwnym razie. Zauważ, że musisz sprawdzić, czy nie ma zbyt długiego kodowania i pustych bajtów (ponieważ jest to Zmodyfikowany UTF-8). Nie musisz dekodować wartości UTF-8.

Przykłady

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

Zasady

  • Obowiązują standardowe zasady i luki
  • Dane wejściowe i wyjściowe mogą być w dowolnym dogodnym formacie, o ile można odczytać wszystkie wartości z zakresu bajtów bez znaku (0–255).
    • Może być konieczne użycie tablicy lub pliku zamiast łańcucha zakończonego znakiem null. Musisz być w stanie odczytać bajty zerowe.
  • Najkrótszy kod wygrywa!
  • Pamiętaj, że użycie wbudowanych narzędzi do dekodowania UTF-8 nie gwarantuje zgodności z podanymi tutaj wymaganiami. Może być konieczne obejście tego i utworzenie specjalnych przypadków.

EDYCJA: dodano premię za nieużywanie wbudowanych funkcji dekodujących UTF-8

EDYCJA 2: usunięto premię, ponieważ kwalifikowała się tylko odpowiedź Rdza i trudno jest zdefiniować.

Wołowina
źródło
Czekałem na to.
Adám
Możesz dodać przypadek testowy z niepoprawnym bajtem z zakresu 0xF8-0xFF.
Arnauld
2
Wydaje się, że surogaty (0xD800 - 0xDFFF) i punkty kodowe poza 0x10FFFF są dozwolone, w przeciwieństwie do „nowoczesnej” specyfikacji UTF-8. Myślę, że należy to wyjaśnić, najlepiej w przypadku dodatkowych przypadków testowych.
nwellnhof,
Przydałoby się więcej przykładów
don Bright
„Bajty z zakresu 0-0x7F włącznie, są zwykle prawidłowe” czy to ma być od 1 do 0x7f?
don bright

Odpowiedzi:

2

Eliksir , 69 bajtów

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

Wypróbuj online!

Wykorzystuje wbudowaną funkcję sprawdzania poprawności ciągu. Pobiera dane wejściowe jako plik binarny Elixir.

Kirill L.
źródło
1

APL (Dyalog Unicode) , 41 39 bajtów SBCS

Anonimowa ukryta funkcja prefiksu. Bierze ciąg Unicode jako argument, w którym punkty kodowe znaków reprezentują bajty wejściowe.

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

Wypróbuj online!

'À\x80'⎕R⎕AR EUmieãæ C0 80s z wielką A lphabet

{} Zastosuj następującą anonimową funkcję, gdzie argumentem jest :

0:: jeśli wystąpi jakikolwiek błąd:

  0 zwróć zero

 próbować:

  ⎕UCS⍵ przekonwertować ciąg na punkty kodowe

  'UTF-8'⎕UCS⍣2 interpretować jako bajty UTF-8 i konwertować wynikowy tekst z powrotem na bajty

  ⌊/ najniższy bajt (zero, jeśli występuje bajt zerowy, dodatni, jeśli nie, „nieskończoność”, jeśli pusty ciąg)

  × znak (zero, jeśli bajt null jest obecny, jeden, jeśli nie jest)

Adám
źródło
Czy to nie zwróciłoby prawdy D9 C0 80 84 C0 80 10?
Neil
@Neil To prawda. Czy to źle, ponieważ usunięcie C0 80powoduje, że niepowiązane bajty sąsiadują ze sobą w prawidłowy sposób, chociaż są one niepoprawne, gdy są oddzielone? Edycja: Zaktualizowano, aby naprawić to bez kosztów bajtów.
Adám
niektóre postacie pojawiają się na moim ekranie jako prostokąty lub pudełka, czy to normalne? Jestem w Firefoxie na Linuksie. APL to bardzo interesujący język.
Don Bright
@donbright Z mojego doświadczenia wynika, znaków APL zawsze czynią poprawnie, nawet jeśli czasami mniej niż pięknie, więc te pudełka są prawdopodobnie tylko Quad s, którego nie powinno być cztery w głównym kodzie. Powinno to wyglądać tak . I tak, APL jest niesamowity i daje dużo zabawy. Możesz łatwo i szybko się tego nauczyć - po prostu przyjdź w APL Orchard .
Adám
tak, to quady. dzięki.
Don Bright
0

Python 2 , 104 102 bajtów

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

Wypróbuj online!

Dane wyjściowe za pośrednictwem kodu wyjścia

TFeld
źródło
0

Rdza - 191 bajtów 313 bajtów

Dla komentarza poniżej oryginału nie działał poprawnie. Nowa i ulepszona wersja. Żadne biblioteki nie są używane, ponieważ Potężna rdza nie potrzebuje ciebie i twoich bibliotek. Ten kod używa dopasowania wzorca z maszyną stanu. Przez bezwstydnie oderwanie spec UTF8 , po znalezieniu go poprzez odniesienie i dyskusji Jon Skeet , możemy skopiować spec prawie znaków dla charakterem do rdzy Meczu bloku wzór meczu. Na koniec dodajemy specjalne wymaganie Mutf8 Beefstera, aby C0 80 został uznany za ważny. Nie golfowany:

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

spróbuj na placu zabaw z rdzą

Don Bright
źródło
Rekwizyty do robienia tego ręcznie, ale myślę, że twoje zbyt długie sprawdzenie jest nieprawidłowe.
Beefster
Wasze wyzwanie, drogi panie, prowokuje mnie do naśladowania, a ja kończę ten list, wzywając was z kolei do postawienia się na człowieku, który ujawni wasze pytanie bardziej otwarcie ( bit.ly/2T8tXhO )
don bright