Celem jest stworzenie w pełni zgodnego konwertera między oficjalnymi kodowaniami Unicode, jak podano w FAQ UTF . Biorąc pod uwagę, że jest on wyśrodkowany na Unicode, zaakceptuję odpowiedź o najniższej liczbie bajtów przy użyciu najlepszego możliwego kodowania (prawdopodobnie będzie to UTF-8, chyba że programujesz go w APL). Przepraszam za długi post, ale wiele z nich wyjaśnia kodowania, do których można również uzyskać dostęp w oficjalnej specyfikacji (pdf, sekcja 3.9 D90 - D92) lub Wikipedia .
Dane techniczne
Jeśli w dowolnym momencie twój wybrany język nie może dokładnie spełnić wymagań, zastąp go czymś, co trzyma się ducha podanych zasad. Na przykład. nie każdy język ma wbudowane tablice, funkcje itp.
Brak korzystania z bibliotek / funkcji ciągów lub bibliotek / funkcji kodowania. Celem tego kodu golfa jest implementacja konwertera za pomocą manipulacji bitami / bajtami. Dozwolone jest jednak używanie samych łańcuchów jako tablicy znaków lub bajtów. Aha, i żadnych wywołań systemu operacyjnego, które wykonałyby konwersję.
Konwerter jest funkcją, która przyjmie trzy parametry: tablicę bajtów reprezentującą zakodowany ciąg wejściowy oraz kodowania „wejściowe” i „wyjściowe” przedstawione w postaci liczb. Arbitralnie przypiszemy
UTF-8, UTF-16, UTF-16BE, UTF-16LE, UTF-32, UTF-32BE, and UTF32LE
liczby od 0 do 6 w tej kolejności. Nie ma potrzeby sprawdzania, czy liczba jest równa< 0
lub> 6
, zakładamy, że parametry te są prawidłowe. Konwerter zwróci prawidłową tablicę bajtów w żądanym kodowaniu wyjściowym.Użyjemy znaku null (
U+0000
) jako terminatora łańcucha. Wszystko po tym nie ma znaczenia. Zakładamy, że tablica wejściowa ma gdzieś znak zerowy, więc nie trzeba sprawdzać granic.Zgodnie z często zadawanymi pytaniami , jeśli tablica bajtów wejściowych jest nieprawidłowa dla zadeklarowanego kodowania, musimy zasygnalizować błąd. Zrobimy to w jeden z następujących sposobów: zawiesimy program, wyrzucimy wyjątek, zwrócimy null lub zwrócimy tablicę, której pierwsze cztery bajty mają wartość 0 (aby można było ją rozpoznać jak
U+0000
w każdym kodowaniu).
Kodowania
Należy przestrzegać oficjalnych specyfikacji, ale Wikipedia zapewnia dobre (i, o ile uważam, poprawne) wyjaśnienie kodowania, i streszczę je tutaj dla kompletności. Zauważ, że UTF-16 i UTF-32 mają warianty endianizmu .
UTF-32, UTF-32LE, UTF-32BE
Najprostsze kodowanie, każdy punkt kodowy jest po prostu zakodowany w 4 bajtach równych jego wartości liczbowej. LE / BE oznacza endianness (little endian / big endian).
UTF-16, UTF-16LE, UTF-16BE
Punkty kodowe z U+0000 - U+FFFF
są zakodowane w 2 bajtach równych wartości liczbowej. Większe wartości są kodowane przy użyciu pary surogatów, które są zastrzeżonymi wartościami z U+D800 - U+DFFF
. Aby zakodować punkty większe niż U+FFFF
, można użyć następującego algorytmu (bezwstydnie skopiowanego z Wikipedii ):
- 0x010000 jest odejmowane od punktu kodowego, pozostawiając 20-bitową liczbę w zakresie 0..0x0FFFFF.
- Dziesięć górnych bitów (liczba w zakresie 0..0x03FF) dodaje się do 0xD800, aby dać pierwszą jednostkę kodu lub wiodące surogat, który będzie w zakresie 0xD800..0xDBFF [...].
- Dziesięć niskich bitów (również w zakresie 0..0x03FF) dodaje się do 0xDC00, aby dać drugą jednostkę kodu lub zastępczą ścieżkę, która będzie w zakresie 0xDC00..0xDFFF [...].
UTF-8
Punkty kodowe z U+0000 - U+007F
są kodowane jako 1 bajt równy wartości liczbowej. Od U+0080 - U+07FF
są one zakodowane jako 110xxxxx 10xxxxxx
, U+0800 - U+FFFF
jest 1110xxxx 10xxxxxx 10xxxxxx
, wyższe wartości 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
. Thex
są bitami od wartości liczbowej punktu kodowego.
BOM
Znak kolejności bajtów (BOM, U+FEFF
) jest używany jako pierwszy punkt kodowy do wskazania endianizmu. Zgodnie z wytycznymi FAQ dotyczącymi BOM , BOM będzie używany w następujący sposób: UTF-8, UTF-16 and UTF-32
ponieważ jest opcjonalny. Jeśli BOM jest nieobecny w UTF-16
lub UTF-32
, zakłada się, że jest to duży endian. LM nie może pojawić się w UTF-16LE, UTF-16BE, UTF-32LE and UTF-32BE
.
Typowe pułapki powodujące nieprawidłowy UTF
Różne rzeczy mogą powodować, że sekwencja bajtów jest niepoprawna UTF.
- UTF-8 i UTF-32: Bezpośrednie kodowanie zastępczych punktów kodowych (
U+D800 - U+DFFF
) lub punktów kodowych większych niżU+10FFFF
. - UTF-8: Wiele nieprawidłowych sekwencji bajtów.
- UTF-16: Niesparowane lub niewłaściwie sparowane zastępcze.
- BOM: Należy użyć zgodnie z opisem w sekcji dotyczącej kodowania. Zauważ, że kiedy wypisujesz
UTF-16
lubUTF-32
(nie określono nieodłącznego endianizmu) możesz wybrać, ale z małym endianem ty musisz dołączyć BOM.
Zauważ, że niepoznakowe i nieprzypisane punkty kodowe (oba różne od zastępczych) należy traktować jak zwykłe znaki.
''⎕R''⍠'InEnc' 'UTF16BE' 'OutEnc' 'UTF8-BOM'
.Odpowiedzi:
C ++, (UTF-8) 971 bajtów
Czytelny program poniżej można skondensować do powyższej postaci, filtrując go za pomocą następującego polecenia Perl:
Powyższe polecenie
#include
linie wokół liniiCzytelny kod
Funkcja nazywać to
t()
, ze kodowanie wejściowe i wyjściowe przekazywane w zmiennych globalnychi
io
odpowiednio, ip
wskazując na bajtów wejściowych, które musi być zakończony zerem.q
wskazuje bufor wyjściowy, który zostanie zastąpiony i musi być wystarczająco duży, aby uzyskać wynik - nie ma próby uniknięcia przekroczenia bufora.Mam nadzieję, że komentarze do kodu są wystarczająco objaśniające - zapytaj poniżej, czy któryś z nich jest zbyt tajemniczy (ale najpierw spróbuj!).
Opracowując tę odpowiedź, opracowałem obszerny zestaw testów; Zamieszczam go poniżej na korzyść innych uczestników oraz w celu udokumentowania mojej interpretacji wymagań:
Funkcje testowe
Zestaw testowy
źródło
Python - 1367 znaków UTF-8
W porządku! Było to niezwykle trudne pytanie ze względu na ogrom pracy, jaką wymagało zrozumienie i wdrożenie wszystkich specyfikacji, ale myślę, że mam poprawną implementację.
convert
to funkcja, która pobiera obiekt „bajty” danych, identyfikator wejściowy i identyfikator wyjściowy. Wygląda na to, że działa - chociaż wydaje się, że Python ma nieco zepsute użycie BOM, gdy nie jest określony w kodowaniu, więc użycie wbudowanego kodowania Pythona do testowania trybów 1 i 4 nie będzie działać.Ciekawostka: rozmiar to również 555 16 lub 10101010101 2 .
773 znaków do dekodowania, 452 do kodowania, 59 do weryfikacji i 83 do różnych części.
źródło
Python 3, 1138 bajtów (UTF-8)
Okazuje się więc, że 14 godzin podróży międzynarodowych to fantastyczna okazja do ukończenia gry w golfa ...
Funkcja konwersji to
C()
. Wywołuje tou()
,v()
iw()
do dekodowania orazU()
,V()
iW()
do kodowania odpowiednio UTF-8, -16 i -32. Żaden z koderów nie wyświetli BOM, ale wszystkie dekodery poprawnie go obsługują. Warunki błędu powodują wyjątek (zwykleZeroDivisionError
dzięki uprzejmości funkcji „umierać nagle”E()
).źródło