Zadanie
Biorąc pod uwagę ciąg znaków UTF-8 (w jakikolwiek sposób) odpowiedź (w jakikolwiek sposób) równoważna lista, w której każdy element jest liczbą bajtów użytych do zakodowania odpowiedniego znaku wejściowego.
Przykłady
!
→ 1
Ciao
→ 1 1 1 1
tʃaʊ
→ 1 2 1 2
Adám
→ 1 1 2 1
ĉaŭ
→ 2 1 2
(pojedyncze znaki)
ĉaŭ
→ 1 2 1 1 2
(używa łączenia nakładek)
チャオ
→ 3 3 3
(puste wejście) →
(puste wyjście)
!±≡𩸽
→ 1 2 3 4
(bajt zerowy) → 1
Brak bajtów
Jeśli jedynym sposobem na utrzymanie odczytu poza bajtami zerowymi jest znajomość całkowitej liczby bajtów, możesz uzyskać liczbę bajtów w jakikolwiek sposób (nawet dane wprowadzone przez użytkownika).
Jeśli twój język nie obsługuje w ogóle bajtów zerowych, możesz założyć, że dane wejściowe nie zawierają wartości zerowych.
Odpowiedzi:
Pyth,
97 bajtówDzięki @Maltysen za uratowanie 2 bajtów!
Zestaw testowy
Konwertuje każdy znak wejściowy na jego reprezentację binarną, a następnie dzieli go na fragmenty o długości 8. Liczba tych fragmentów jest wtedy ilością bajtów potrzebną do zakodowania tego znaku.
źródło
.E
pyth.herokuapp.com/…mlhc8.B
ml%8.B
(terazd
jest to domniemane).Python 3,
4236 bajtówźródło
map
.lambda x:map(len,map(str.encode,x))
C,
6865 bajtówDzięki @FryAmTheEggman za grę w golfa na 3 bajtach!
Przetestuj na Ideone .
źródło
APL, 15 znaków
W języku angielskim: przekonwertuj każdy znak na UTF-8 (co oznacza wektor reprezentacji bajtów) i uzyskaj jego sumę.
źródło
≢¨'UTF-8'∘⎕ucs¨
+⌿0 7 11 16∘.≤2⍟⎕UCS
0 7 11 16⍸2⍟⎕UCS
GolfScript, 16 bajtów
Wypróbuj online!
tło
GolfScript nie ma pojęcia, czym jest Unicode; wszystkie ciągi (wejściowe, wyjściowe, wewnętrzne) składają się z bajtów. To może być dość denerwujące, ale jest idealne do tego wyzwania.
UTF-8 inaczej koduje znaki ASCII i inne niż ASCII:
Wszystkie punkty kodowe poniżej 128 są zakodowane jako
0xxxxxxx
.Wszystkie pozostałe punkty kodowe są zakodowane jako
11xxxxxx 10xxxxxx ... 10xxxxxx
.Oznacza to, że kodowanie każdego znaku Unicode zawiera albo jeden
0xxxxxxx
bajt, albo jeden11xxxxxx
bajt i 1 do 510xxxxxx
bajtów.Dzieląc wszystkie bajty danych wejściowych przez 64 , zamieniamy
0xxxxxxx
na 0 lub 1 ,11xxxxxx
na 3 i10xxxxxx
na 2 .Jeśli porównamy iloraz z 2 - wypychanie 1 do 2 ; i 0 dla 0 , 1 i 3 - każdy znak zostanie zamieniony na 0 , a następnie od 1 do 5 1 .
Pozostało tylko podzielić wynikowy ciąg w wystąpieniach 0 , policzyć liczbę 1 między zerami i dodać jeden do kwoty.
Jak to działa
źródło
PowerShell v4, 58 bajtów
NB
OK, to powinno działać i działa w prawie wszystkich testowych przypadkach, z wyjątkiem
𩸽
których w jakiś sposób jest to liczone jak3,3
na moim komputerze. Ten znak pokazuje nawet 7 bajtów na moim komputerze. Podejrzewam, że jest to spowodowane jakimś błędem w wersji Windows lub .NET, którą uruchamiam lokalnie, ponieważ @Mego nie ma tego problemu . ( Edycja: @cat wskazuje, że przyczyną jest BOM . Dziękujemy za rozwiązanie tej zagadki, @cat! )Jednak nadal nie stanowi to całego problemu. Myślę jednak, że wiem, skąd biorą się niektóre problemy. Wewnątrz .NET wszystkie ciągi znaków składają się z jednostek kodu UTF-16 (typu System.Char). Dzięki bardzo luźnemu rzutowaniu czcionek używanemu przez PowerShell, istnieje wiele niejawnych rzutowań i konwersji między typami w tle. Prawdopodobnie jest to czynnik przyczyniający się do zachowania, które widzimy - na przykład
[system.text.encoding]::utf8.getchars([System.Text.UTF8Encoding]::UTF8.GetBytes('𩸽'))
zwraca dwa niedrukowalne, a nie pojedynczy znak.Wyjaśnienie
Bardzo prosty kod. Pobiera dane wejściowe
$args[0]
i jawnie rzutuje je jako tablicę znaków, dzięki czemu możemy zapętlić każdy składnik łańcucha|%{...}
. W każdej iteracji używamy wywołania .NET[System.Text.Encoding]::UTF8.GetByteCount()
(System.
implikowane), aby uzyskać liczbę bajtów bieżącego znaku$_
. To jest umieszczane w potoku dla późniejszego wyjścia. Ponieważ jest[int]
to zwracana kolekcja s, rzutowanie na tablicę jest niejawne.Testuje się
Edytowane w celu dodania To poprawnie uwzględnia wymóg zerowy bajtów, który został dodany do wyzwania po tym, jak pierwotnie opublikowałem, pod warunkiem, że pobierzesz dane z pliku tekstowego i potokujesz go w następujący sposób:
źródło
That character even shows as 7 bytes on my computer.
Tak, to z powodu Znaku Bajt, który dostajesz w systemie Windows dzięki UTF-8. Powiedz Notepad ++, aby używałUTF-8 without BOM
(jak zawsze powinieneś unikać BOM , szczególnie dla kompatybilności z Unicies), a zobaczysz, że plik ma rozmiar 4 bajtów, ponieważ BOM to 3 i 4 + 3 = 7get-content -Encoding UTF8 .\z.txt|%{.\bytes-per-character.ps1 $_}
nadal powraca3,3
.-Encoding
parametr nie wydaje się obsługiwany .JavaScript (ES6),
544543 bajtówEdycja: Zapisano 2 bajty przy pomocy @ l4m2.
źródło
s=>[...s].map(c=>encodeURI(c).length/3-4&3)
Rubinowy, 33 bajty
Ledwo wyostrza się Python, tak! Wypróbuj online.
źródło
Perl 6 ,
77 6963 bajtówPonieważ Perl 6 używa ciągów NFG, muszę pobierać bajty bezpośrednio, co omija tę funkcję.
(NFG jest jak NFC, z tym że tworzy również syntetyczne złożone współrzędne kodowe)
Dane wyjściowe są oddzielone znakami nowej linii.
Test:
Wyjaśnienie:
Działa to, ponieważ pierwszy bajt w wielobajtowym punkcie kodowym ma liczbę bajtów zakodowanych w nim, a pozostałe bajty w punkcie kodowym mają najwyższy ustawiony bit, ale nie następny najwyższy. Podczas gdy jednobajtowe punkty kodowe nie mają ustawionego najwyższego bitu.
źródło
read:1
i / lub/while$
zamiast tego? A jeśli to zadziałaif$
?while
.\n1\n1\n
, czy jest to celowe? Zasadniczo, czy obsługuje to bajty NUL?perl -e 'print "𩸽\0𩸽"' | perl6 -e '...'
robię się414
tak, jakbym się spodziewał. (Część o nulsach została dodana po tym, jak opublikowałem)Python 3, 82 bajty
Jest to znacznie dłużej niż w przypadku innej odpowiedzi w języku Python i większości innych odpowiedzi, ale stosuje podejście obejmujące logarytmy, których jeszcze nie widziałem.
Anonimowa funkcja, która pobiera dane wejściowe za pomocą argumentu jako ciąg znaków i zwraca listę.
Wypróbuj na Ideone
Jak to działa
Ta metoda opiera się na sposobie, w jaki UTF-8 koduje punkt kodowy znaku. Jeśli punkt kodowy jest mniejszy niż 128, znak jest kodowany jak w ASCII:
gdzie
x
reprezentuje bity punktu kodowego. Jednak w przypadku punktów kodowych większych lub równych 128 pierwszy bajt jest uzupełniany taką samą liczbą1
s, jak całkowita liczba bajtów, i rozpoczynają się kolejne bajty10
. Bity punktu kodowego są następnie wprowadzane, aby dać możliwie najkrótszą sekwencję wielobajtową, a wszelkie pozostałe bity stają się0
.i tak dalej.
Można teraz zauważyć, że dla każdej liczby bajtów
n
górna granica liczby bitów kodu jest podana przez(-n+7)+6(n-1) = 5n+1
. W związku z tym górny limitc
dla każdego kodun
jest podawany dziesiętnie przezc= 2^(5n+1)
. Zmiana układu daje ton = (log2(c)-1)/5
. Tak więc dla dowolnego punktu kodowego liczbę bajtów można znaleźć, oceniając powyższe wyrażenie, a następnie biorąc pod uwagę pułap.Nie działa to jednak w przypadku punktów kodowych w zakresie
64 <= c <= 127
, ponieważ brak dopełnienia1
spowodowany kodowaniem podobnym do ASCII dla 1-bajtowych znaków oznacza, że przewidywana jest niepoprawna górna granica ilog2
jest ona niezdefiniowanac = 0
, co dzieje się, gdy bajt zerowy jest obecny na wejściu. Dlatego jeślic <= 127
wartość1
jest zwracana dla n.To właśnie robi kod; dla każdego znaku
i
w ciągux
kod-punkt znajduje się za pomocąord
funkcji, a pułap wyrażenia znajduje się za pomocą liczby całkowitej zamiast dzielenia zmiennoprzecinkowego,5
a następnie dodając1
. Ponieważ typ zmiennoprzecinkowy Pythona zawsze reprezentuje liczby całkowite, ponieważx.0
nawet po dzieleniu liczb całkowitych wynik jest przekazywany doint
funkcji w celu usunięcia końcowego zera. Jeśliord(i) <= 127
logiczne zwarcie oznacza, że1
jest ono zwracane. Liczba bajtów dla każdego znaku jest przechowywana jako element na liście i ta lista jest zwracana.źródło
Java 10,
10096956761 bajtów-4 bajty usuwające spacje, ponieważ jest to dozwolone w komentarzach
-1 bajt zmienia się
UTF-8
nautf8
-28 bajtów z Java 7 na 8 (
a->{...}
zamiastvoid c(char[]i)throws Exception{...}
)-3 bajty przyjmując dane wejściowe jako tablicę ciągów zamiast tablicy znaków i
-3 bajty przejście z Javy 8 na 10 (
var
zamiastString
)Wyjaśnienie:
Wypróbuj online.
źródło
Julia, 34 bajty
Jest to anonimowa funkcja, która przyjmuje ciąg znaków i zwraca tablicę liczb całkowitych. Aby go wywołać, przypisz go do zmiennej.
Podejście jest dość proste: jeśli wejście jest puste, wyjście jest puste. W przeciwnym razie odwzorowujemy
sizeof
funkcję, która liczy liczbę bajtów w ciągu, na każdy podłańcuch jednoznakowy.Wypróbuj online! (obejmuje wszystkie przypadki testowe)
źródło
s->[sizeof("$c")for c=s]
oszczędza kilka bajtów.split("","")
nie wrócić[]
? (JavaScript"".split("")
robi.)split("","")
wydaje się dać""
(inaczej niż w Pythonie, który daje wyjątek), ale nie wiem nic na temat zgodności wiedzieć[]
i""
w Julii.split("", "") == [""]
tj. Tablica jednoelementowa zawierająca pusty ciąg znaków, ale problem polega na tymsizeof("") == 0
, że według OP nie jest dozwolone.PHP,
9257 bajtówPo zastanowieniu możesz to zrobić przy znacznie mniejszym rozdrabnianiu:
Wypróbuj online, zauważ, że jest to nieco dłużej, ponieważ używa stdin zamiast argumentu programu.
Ta wersja wymaga zignorowania powiadomień wysyłanych do stderr, ale to w porządku .
stara wersja:
używa innego podejścia do innej odpowiedzi php. Opiera się na braku natywnej obsługi ciągów wielobajtowych w php.
źródło
<?=
Emacs Lisp,
5549 bajtówNajpierw dzieli ciąg na listę znaków z
(mapcar 'string s)
.string
Funkcję w Emacs Lisp przyjmuje wykaz znaków i tworzy ciąg z nich. Ze względu na sposób, w jaki Emacs dzieli ciągi znakówmapcar
(tj. Na listę liczb całkowitych, a nie znaków lub ciągów), ta wyraźna konwersja jest konieczna. Następnie mapujestring-bytes
funkcję na tę listę ciągów.Przykład:
Przypadki testowe:
Stara odpowiedź:Nie golfowany:
Przypadki testowe:
źródło
nil
jeśli spłaszczysz wynik?nil
to pusta lista (i jedyny sposób, aby powiedzieć „fałsz” w Emacsie). Chociaż w Emacsie nie ma standardowego spłaszczenia (możesz użyć myślnika-flatten
), każda możliwa implementacja go wyeliminowałaby.JavaScript (węzeł), 27 bajtów
Pobiera dane wejściowe jako tablicę pojedynczych znaków i zwraca tablicę zliczeń bajtów.
Buffer
to metoda reprezentowania surowych danych binarnych. Buffer.byteLength (string) podaje liczbę bajtów w ciągu. UTF-8 jest domyślnym kodowaniem. Zauważ, że tylko Node.js ma bufory, a nie JS przeglądarki. Z grubsza odpowiednik przeglądarki nazywa się Blob , który ma 31 bajtów:Test
Zapisz ten plik i uruchom go przez węzeł lub wypróbuj online .
To powinien być wynik:
źródło
Bash, 74 bajty
Grał w golfa
Algorytm
ciąg wejściowy hexdump, złóż 2 znaki w wierszu, wytnij tylko pierwszy znak
(4 bity wysokiego rzędu każdego bajtu wejściowego jako znak szesnastkowy, po jednym w wierszu)
Usuń „bajty kontynuacji” 0x80..0xBF
(pozostało 4 bity pierwszego bajtu każdego znaku Unicode)
zamapuj pierwsze bity na długość char, zwiń wyjście i wydrukuj
Test
źródło
-t
Opcjatr
nie znał mnie i widocznie rozszerzeniem GNU. Rurociągi do zastępowania poleceń poecho
mogą być również warte nieco bardziej szczegółowego wyjaśnienia.PHP, 126 bajtów
Wypróbuj online!
źródło
<?=($s=fgets(STDIN))?
C #,
8982 bajtówProsta lambda C #, która iteruje ciąg i zwraca listę rozdzieloną spacjami.
Edycja: zapisano 6 bajtów dzięki bardzo fajnym komentarzom.
źródło
var J="";...
1121
i1 2 1 2
to zarówno OK} return J;};
using System.Text
lub gdzieś tam - import nie jest darmowy.Haskell, 85 bajtów
źródło
map$...
Pyth, 17 bajtów
Wypróbuj online!
Użyj punktu kodowego znaków z pewną arytmetyką.
źródło
C, 85 bajtów.
Bada wysokie 4 bity każdego bajtu, aby określić kodowanie i liczbę kolejnych bajtów do pominięcia;
źródło
while *c
wyjścia na pusty ciąg znaków, a `c + = d 'pomija nulls w środku wielobajtowego punktu kodowego.char*
naprawdę) w C jest oznaczony bajtem zerowym. Niemożliwe jest odróżnienie bajtów zerowych od rzeczywistego końca łańcucha.Współczynnik,
57878280 bajtówWyjaśnił:
Testy jednostkowe:
Teraz wszyscy przechodzą. do:
źródło
Swift 2.2,
675250 bajtówOkropnie brzydka. Nie ma sposobu, aby uzyskać długość UTF-8 postaci w Swift, więc muszę iterować ciąg po znaku, przekonwertować na
Character
aString
i znaleźćcount
tę pojedynczą postaćString
(hej, przynajmniej jest wbudowana metoda, aby to zrobić). Szukasz optymalizacji, prawdopodobnie przy użyciu skanera.Wersja 1: Zapisano 15 bajtów, używając
count
zamiastunderestimateCount()
.Rewizje 2: Zapisano kolejne 2 znaki, używając pętli for-in zamiast a dla każdego zamknięcia.
źródło
Rdza, 53 bajty
Rdza ma prymitywy znaków utf-8, iteratory i lambdy, więc było to proste. Kod testowy:
Wyjścia
źródło
jq, 26 znaków
(23-znakowy kod + 3-znakowa opcja wiersza poleceń)
Mam nadzieję, że konkuruje. Chociaż
utf8bytelength
został dodany 9 ++ miesięcy przed tym pytaniem, to nie jest jeszcze uwzględnione w wersji wydany.Przykładowy przebieg:
źródło
C (gcc) , 53 bajty
Wypróbuj online!
źródło
SmileBASIC, 69 bajtów
Dane wejściowe to tablica bajtów.
Liczba bajtów w znaku UTF-8 jest równa liczbie
1
bitów wiodących w pierwszym bajcie (chyba że nie ma żadnych1
znaków, w którym to przypadku jest to 1 bajt). Aby znaleźć liczbę wiodących 1, program znajduje pierwszy0
w reprezentacji binarnej, a następnie dodaje 1, jeśli było to 0.źródło
F #,
595466 bajtówTechnicznie rzecz biorąc, s jest sekwencją char, ale okazuje się, że istnieje niejawna konwersja, która pozwala na przekazanie łańcucha.
Podczas testowania tego w konsoli
!±≡𩸽
dzieli kanji na dwa znaki o długości 3 bajtów. Wszystkie pozostałe przypadki testowe działają dobrze.Edycja: Okazuje się, że importowanie wspólnej przestrzeni nazw nie jest niejawne. Kolejne 12 znaków.
źródło
UTF-8 without BOM
to jest to błędne i powinno zostać naprawione. 3) Wydaje się, że F # wymaga stwierdzeń,let f(x)= ...
które kończą się;;
, jak SML. 4) Możesz przerwać przypisywanie tej anonimowej funkcji nazwy, tj(s)=seq{for c in s->Encoding.UTF8.GetByteCount([|c|])}
.error FS0039: The namespace or module 'Encoding' is not defined
gdy próbuję to uruchomić. Co ja robię źle?System.Text
przestrzeń nazw. Zakładam, że przestrzeń nazw otwiera się i kod dostępu jest uwzględniony, pochodzący z odpowiedzi C # AstroDan.import
,#include
,open
,load
,require
,using
,USING:
etc tutaj na PPCG. Odpowiedź C # AstroDana jest podobnie błędna i powiadomiłem ich o tym.05AB1E , 15 bajtów
Wypróbuj online.
Nagłówek
ε
jest używany dla każdego ze wszystkich przypadków testowych;Stopka
ï]J]»
do wydrukowania list znaków wyjściowych (ï
: dziesiętne i znaki do liczb całkowitych;:]
zamknij if-else i for-eachJ
;: Połącz cyfry razem}
:: zamknij foreach nagłówka;:»
Dołącz przez nowe wiersze).Wyjaśnienie:
Ponieważ 05AB1E nie ma żadnych wbudowanych funkcji do konwersji znaków na liczbę użytych bajtów, używam
Ç
do konwersji znaków na ich wartości Unicode, a dla każdego z nich wykonaj następujące czynności w pseudokodzie:Zainspirowany odpowiedzią Python 3 na TheBikingViking .
źródło
Zsh , 41 bajtów
Wypróbuj online!
Zsh rozpoznaje UTF-8, więc podzieliliśmy ciąg znaków na znaki, następnie wyłączamy wielobajty i wypisujemy długość każdego znaku.
źródło