Bajty / Postać


28

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

Ciao1 1 1 1

tʃaʊ1 2 1 2

Adám1 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.


1
Jeśli dane wejściowe są puste, czy możemy wyprowadzić 0 lub inną wartość falsey?
Alex A.

2
Czy mogę wydrukować liczby bajtów bez separacji? Najwyższą możliwą wartością jest 6, więc jest jednoznaczna.
Dennis

3
Czy musimy obsługiwać bajty zerowe? To może być prawdziwy ból w niektórych językach ...
Dennis

3
Powinieneś dodać to do postu. Nie znam większości języków na tyle dobrze, aby stwierdzić, czy to robi różnicę, ale myślę, że unieważnia co najmniej dwie odpowiedzi.
Dennis

2
@ Adám tak będzie. Na przykład w C ciągi C kończą się bajtem NUL, więc przestajesz czytać, jak tylko je znajdziesz. Jeśli znasz długość łańcucha, przestajesz czytać po tylu bajtach, NUL i wszystkich innych.
kot

Odpowiedzi:


10

Pyth, 9 7 bajtów

Dzięki @Maltysen za uratowanie 2 bajtów!

mlc.Bd8

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.


1
możesz zaoszczędzić 2 bajty dzięki dzieleniu zamiast dzieleniu, a następnie usuwaniu .E pyth.herokuapp.com/…
Maltysen

@Maltysen To sprytne, dzięki!
Denker

1
Ta sama długość odpowiedzi, która opiera się na podobnej sztuczce:mlhc8.B
FryAmTheEggman

@LeakyNun to byłoby proste dać test, który się nie powiedzie, prawda?
Lause

Aby zapisać kolejny bajt, zamiast dzielenia na 8-częściowe, bierz co 8-te: ml%8.B(teraz djest to domniemane).
Anders Kaseorg,


11

C, 68 65 bajtów

b;main(c){for(;~c;b=c/64^2?b?putchar(b+48)/48:1:b+1)c=getchar();}

Dzięki @FryAmTheEggman za grę w golfa na 3 bajtach!

Przetestuj na Ideone .


11

APL, 15 znaków

≢¨'UTF-8'∘⎕ucs¨

W języku angielskim: przekonwertuj każdy znak na UTF-8 (co oznacza wektor reprezentacji bajtów) i uzyskaj jego sumę.


Zapisz bajt:≢¨'UTF-8'∘⎕ucs¨
Adám

Rzeczywiście @ Adám ... Pozdrawiam.
lstefano

Ciekawe (ale dłuższe) podejście oparte na tablicy:+⌿0 7 11 16∘.≤2⍟⎕UCS
Adám

Wersja 16.0:0 7 11 16⍸2⍟⎕UCS
Adám

7

GolfScript, 16 bajtów

{64/2=}%1,/{,)}*

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 0xxxxxxxbajt, albo jeden 11xxxxxxbajt i 1 do 5 10xxxxxxbajtów.

Dzieląc wszystkie bajty danych wejściowych przez 64 , zamieniamy 0xxxxxxxna 0 lub 1 , 11xxxxxxna 3 i 10xxxxxxna 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

{     }%          Map the following over all bytes in the input.
 64/                Divide the byte by 64.
    2=              Compare the quotient with 2, pushing 1 or 0.
        1,        Push range(1), i.e., [0].
          /       Split the array of Booleans around zeroes.
           {  }*  Fold; for each run of ones but the first:
            ,       Push its length.
             )      Increment.

6

PowerShell v4, 58 bajtów

[char[]]$args[0]|%{[Text.Encoding]::UTF8.GetByteCount($_)}

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 jak 3,3na 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ę

PS C:\Tools\Scripts\golfing> .\bytes-per-character.ps1 'tʃaʊ'
1
2
1
2

PS C:\Tools\Scripts\golfing> .\bytes-per-character.ps1 'Adám'
1
1
2
1

PS C:\Tools\Scripts\golfing> .\bytes-per-character.ps1 'ĉaŭ'
2
1
2

PS C:\Tools\Scripts\golfing> .\bytes-per-character.ps1 'ĉaŭ'
1
2
1
1
2

PS C:\Tools\Scripts\golfing> .\bytes-per-character.ps1 'チャオ'
3
3
3

PS C:\Tools\Scripts\golfing> .\bytes-per-character.ps1 '!±≡𩸽'
1
2
3
3
3

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:

PS C:\Tools\Scripts\golfing> gc .\z.txt -Encoding UTF8|%{.\bytes-per-character.ps1 $_}
2
1
1
1

z.txt


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 = 7
cat

@ kot Ah, tak, to ma sens. OK, aby uwzględnić różnicę rozmiarów plików. Jednak nadal nie tłumaczy to różnych zachowań wewnątrz samej powłoki. Na przykład zapisanie go jako UTF-8 bez BOM i uruchomienie get-content -Encoding UTF8 .\z.txt|%{.\bytes-per-character.ps1 $_}nadal powraca 3,3.
AdmBorkBork


Ale najwyraźniej i tak działa dobrze
AdmBorkBork

6

JavaScript (ES6), 54 45 43 bajtów

s=>[...s].map(c=>encodeURI(c).length/3-8&7)

Edycja: Zapisano 2 bajty przy pomocy @ l4m2.


s=>[...s].map(c=>encodeURI(c).length/3-4&3)
14m2

@ l4m2 To się nie udaje dla znaków spoza BMP, ale udało mi się to naprawić.
Neil,


5

Perl 6 ,  77 69  63 bajtów

put +$0 if $_».base(2).fmt("%8d")~~/^(1)**2..*|^(" ")/ while $_=$*IN.read: 1
put +$0 if $_».fmt("%8b")~~/^(1)**2..*|^(" ")/ while $_=$*IN.read: 1

put 1+$0 if $_».fmt("%8b")~~/^1(1)+|^" "/while $_=$*IN.read: 1
put 1+$0 if $_».fmt("%0.8b")~~/^1(1)+|^0/while $_=$*IN.read: 1

Ponieważ 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:

for text in '!' 'Ciao' 'tʃaʊ' 'Adám' 'ĉaŭ' 'ĉaŭ' 'チャオ' '' '!±≡𩸽' '𩸽\0𩸽';
do
  echo -en $text |
  perl6 -e 'put 1+$0 if $_».fmt("%8b")~~/^1(1)+|^" "/while $_=$*IN.read: 1' |

  # combine all of the lines into a single one for display purposes
  env text=$text perl6 -e 'put qq["%*ENV<text>"], "\t\t", lines.gist'
done
"!"     (1)
"tʃaʊ"      (1 2 1 2)
"Adám"      (1 1 2 1)
"ĉaŭ"       (2 1 2)
"ĉaŭ"     (1 2 1 1 2)
"チャオ"       (3 3 3)
""      ()
"!±≡𩸽"     (1 2 3 4)
"𩸽\0𩸽"        (4 1 4)

Wyjaśnienie:

# turns the list in 「$0」 into a count, and adds one
# 「put」 prints that with a trailing newline
put 1+$0 

   # if the following is true
   if

       # format the input byte to base 2 and pad it out to 8 characters
       $_».fmt("%8b")

       ~~ # smart match against

       # check to see if it starts with more than one 1s, or a space
       # ( also sets 「$0」 to a list that is 1 shorter
       # than the number of bytes in this codepoint )
       / ^1 (1)+ | ^" " /

           # for every byte in STDIN
           while
               $_ = $*IN.read: 1

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.


Nie możesz zrobić read:1i / lub /while$zamiast tego? A jeśli to zadziała if$?
Erik the Outgolfer

@ EʀɪᴋᴛʜᴇGᴏʟғᴇʀ Nie, ponieważ byłoby to analizowane jako coś innego. Mogę jednak wcześniej usunąć przestrzeń while.
Brad Gilbert b2gills

Czy potrafisz wyjaśnić środki zaradcze NFG?
JDługosz

Jeśli powtórzę bajt NUL do STDIN tego programu, zostanie wydrukowane \n1\n1\n, czy jest to celowe? Zasadniczo, czy obsługuje to bajty NUL?
kot

@cat Dlaczego by tego nie zrobić? Kiedy to robię: perl -e 'print "𩸽\0𩸽"' | perl6 -e '...'robię się 4␤1␤4tak, jakbym się spodziewał. (Część o nulsach została dodana po tym, jak opublikowałem)
Brad Gilbert b2gills

5

Python 3, 82 bajty

import math
lambda x:[ord(i)<128and 1or int((math.log2(ord(i))-1)//5+1)for i in x]

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:

0xxxxxxx

gdzie xreprezentuje bity punktu kodowego. Jednak w przypadku punktów kodowych większych lub równych 128 pierwszy bajt jest uzupełniany taką samą liczbą 1s, jak całkowita liczba bajtów, i rozpoczynają się kolejne bajty 10. Bity punktu kodowego są następnie wprowadzane, aby dać możliwie najkrótszą sekwencję wielobajtową, a wszelkie pozostałe bity stają się 0.

No. of bytes  Format
1             0xxxxxxx
2             110xxxxx 10xxxxxx
3             1110xxxx 10xxxxxx 10xxxxxx
4             11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
...           ...

i tak dalej.

Można teraz zauważyć, że dla każdej liczby bajtów ngórna granica liczby bitów kodu jest podana przez (-n+7)+6(n-1) = 5n+1. W związku z tym górny limit cdla każdego kodu njest podawany dziesiętnie przez c= 2^(5n+1). Zmiana układu daje to n = (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łnienia 1spowodowany kodowaniem podobnym do ASCII dla 1-bajtowych znaków oznacza, że ​​przewidywana jest niepoprawna górna granica i log2jest ona niezdefiniowana c = 0, co dzieje się, gdy bajt zerowy jest obecny na wejściu. Dlatego jeśli c <= 127wartość 1jest zwracana dla n.

To właśnie robi kod; dla każdego znaku iw ciągu xkod-punkt znajduje się za pomocą ordfunkcji, a pułap wyrażenia znajduje się za pomocą liczby całkowitej zamiast dzielenia zmiennoprzecinkowego, 5a następnie dodając 1. Ponieważ typ zmiennoprzecinkowy Pythona zawsze reprezentuje liczby całkowite, ponieważ x.0nawet po dzieleniu liczb całkowitych wynik jest przekazywany do intfunkcji w celu usunięcia końcowego zera. Jeśli ord(i) <= 127logiczne zwarcie oznacza, że 1jest ono zwracane. Liczba bajtów dla każdego znaku jest przechowywana jako element na liście i ta lista jest zwracana.


5

Java 10, 100 96 95 67 61 bajtów

a->{for(var c:a)System.out.print(c.getBytes("utf8").length);}

-4 bajty usuwające spacje, ponieważ jest to dozwolone w komentarzach
-1 bajt zmienia się UTF-8na utf8
-28 bajtów z Java 7 na 8 ( a->{...}zamiast void 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 ( varzamiast String)

Wyjaśnienie:

Wypróbuj online.

a->{                      // Method with String-array parameter and no return-type
  for(var c:a)            //  Loop over the input-array
    System.out.print(     //   Print:
      c.getBytes("utf8")  //    The bytes as array in UTF-8 of the current item,
       .length);}         //    and print the amount of bytes in this array

Czy to działa dla bajtów zerowych?
kot

@cat Później dodano przypadek testowy dla pustych bajtów. Ale tak, działa również dla zerowych bajtów i dodałem przypadek testowy.
Kevin Cruijssen

3

Julia, 34 bajty

s->s>""?map(sizeof,split(s,"")):[]

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 sizeoffunkcję, która liczy liczbę bajtów w ciągu, na każdy podłańcuch jednoznakowy.

Wypróbuj online! (obejmuje wszystkie przypadki testowe)


s->[sizeof("$c")for c=s]oszczędza kilka bajtów.
Dennis

Dziwny; czy split("","")nie wrócić []? (JavaScript "".split("")robi.)
Neil

@Neil 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.
kot

@Neil Nie, split("", "") == [""]tj. Tablica jednoelementowa zawierająca pusty ciąg znaków, ale problem polega na tym sizeof("") == 0, że według OP nie jest dozwolone.
Alex A.,

@Dennis To się nie powiedzie w przypadku nieindeksowalnych ciągów. (Nie mogę jednak wymyślić przykładu od razu.)
Alex A.

3

PHP, 92 57 bajtów

Po zastanowieniu możesz to zrobić przy znacznie mniejszym rozdrabnianiu:

<?php for(;$a=strlen(mb_substr($argv[1],$i++,1));)echo$a;

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.

<?php for($l=strlen($a=$argv[1]);$a=mb_substr($a,1);$l=$v)echo$l-($v=strlen($a));echo$l?:'';

Niezła odpowiedź! Myślę, że możesz całkowicie upuścić tag otwierający lub zmienić go na<?=
cat

Bez tagu jest to fragment kodu, a nie program, a nawet jeśli jest to dozwolone, sprawia, że ​​czuję się niejasno brudny. Z alternatywnym znacznikiem pojawia się błąd analizy (lub przynajmniej zrobiłem to na php 5.5, do czego jestem przyzwyczajony).
user55641

Ok :) Nie wiem PHP (nie chcę, kaszel ), ale będę cię tu wskazać: codegolf.stackexchange.com/questions/2913
kot

3

Emacs Lisp, 55 49 bajtów

(lambda(s)(mapcar'string-bytes(mapcar'string s)))

Najpierw dzieli ciąg na listę znaków z (mapcar 'string s). stringFunkcję 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ów mapcar(tj. Na listę liczb całkowitych, a nie znaków lub ciągów), ta wyraźna konwersja jest konieczna. Następnie mapuje string-bytesfunkcję na tę listę ciągów.

Przykład:

(mapcar 'string "abc") ; => ("a" "b" "c")
(mapcar 'string-bytes '("a" "b" "c")) ; => (1 1 1) 

Przypadki testowe:

(mapcar
 (lambda(s)(mapcar'string-bytes(mapcar'string s)))
 '("!""Ciao""tʃaʊ""Adám""ĉaŭ""ĉaŭ""チャオ""""!±≡𩸽""\0"))
;; ((1) (1 1 1 1) (1 2 1 2) (1 1 2 1) (2 1 2) (1 2 1 1 2) (3 3 3) nil (1 2 3 4) (1))

Stara odpowiedź:

(lambda(s)(mapcar(lambda(s)(string-bytes(string s)))s))

Nie golfowany:

 (lambda (s)
   (mapcar
    ;; we can't use string-bytes directly,
    ;; since Emacs mapcar yields a list of ints instead of characters
    ;; therefore we need a wrapper function here. 
    (lambda (s)
      (string-bytes (string s)))
    s))

Przypadki testowe:

(mapcar
 (lambda(s)(mapcar(lambda(s)(string-bytes(string s)))s))
 '("!""Ciao""tʃaʊ""Adám""ĉaŭ""ĉaŭ""チャオ""""!±≡𩸽""\0"))
;; ((1) (1 1 1 1) (1 2 1 2) (1 1 2 1) (2 1 2) (1 2 1 1 2) (3 3 3) nil (1 2 3 4) (1))


Co stanie się, niljeśli spłaszczysz wynik?
Adám

1
@ Adám nilto 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.
Lord Yuuma,

3

JavaScript (węzeł), 27 bajtów

s=>s.map(Buffer.byteLength)

Pobiera dane wejściowe jako tablicę pojedynczych znaków i zwraca tablicę zliczeń bajtów.

Bufferto 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:

s=>s.map(e=>new Blob([e]).size)

Test

Zapisz ten plik i uruchom go przez węzeł lub wypróbuj online .

var f =
  s=>s.map(Buffer.byteLength)

var tests = [
  ["!"],
  ["C","i","a","o"],
  ["t","ʃ","a","ʊ"],
  ["A","d","á","m"],
  ["ĉ","a","ŭ"],
  ["c","̂","a","u","̆"],
  ["チ","ャ","オ"],
  [],
  ["!","±","≡","𩸽"]
];

tests.forEach(test => {
  console.log(test, f(test));
});

To powinien być wynik:

$ node bytes.js
[ '!' ] [ 1 ]
[ 'C', 'i', 'a', 'o' ] [ 1, 1, 1, 1 ]
[ 't', 'ʃ', 'a', 'ʊ' ] [ 1, 2, 1, 2 ]
[ 'A', 'd', 'á', 'm' ] [ 1, 1, 2, 1 ]
[ 'ĉ', 'a', 'ŭ' ] [ 2, 1, 2 ]
[ 'c', '̂', 'a', 'u', '̆' ] [ 1, 2, 1, 1, 2 ]
[ 'チ', 'ャ', 'オ' ] [ 3, 3, 3 ]
[] []
[ '!', '±', '≡', '�' ] [ 1, 2, 3, 4 ]

3

Bash, 74 bajty

Grał w golfa

xxd -p|fold -2|cut -c1|tr -d '89ab'|echo `tr -t '01234567cbef' '[1*]2234'`

Algorytm

ciąg wejściowy hexdump, złóż 2 znaki w wierszu, wytnij tylko pierwszy znak

echo -ne '!±≡𩸽' | xxd -p|fold -2|cut -c1

2
c
b
e
8
a
f
a
b
b

(4 bity wysokiego rzędu każdego bajtu wejściowego jako znak szesnastkowy, po jednym w wierszu)

Usuń „bajty kontynuacji” 0x80..0xBF

tr -d '89ab'

2
c

e


f

(pozostało 4 bity pierwszego bajtu każdego znaku Unicode)

zamapuj pierwsze bity na długość char, zwiń wyjście i wydrukuj

echo `tr -t '01234567cbef' '[1*]2234'`

1 2 3 4

Test

 U() { xxd -p|fold -2|cut -c1|tr -d '89ab'|echo `tr -t '01234567cbef' '[1*]2234'`;}

 echo -ne '!' | U 
 1

 echo -ne 'Ciao' | U
 1 1 1 1

 echo -ne 'tʃaʊ' | U
 1 2 1 2

 echo -ne 'Adám' | U
 1 1 2 1

 echo -ne 'ĉaŭ' | U
 2 1 2

 echo -ne 'ĉaŭ' | U
 1 2 1 1 2

 echo -ne 'チャオ' | U
 3 3 3
 echo -ne '!±≡𩸽' | U
 1 2 3 4

 echo -ne "\x0" | U
 1

 echo -ne '' | U

+1 Ładne podejście. Rzeczywiście odczytujesz wynik bezpośrednio z wejścia.
Adám

-tOpcja trnie znał mnie i widocznie rozszerzeniem GNU. Rurociągi do zastępowania poleceń po echomogą być również warte nieco bardziej szczegółowego wyjaśnienia.
tripleee


2

C #, 89 82 bajtów

I=>{var J="";foreach(char c in I){J+=Encoding.UTF8.GetByteCount(c+"");}return J;};

Prosta lambda C #, która iteruje ciąg i zwraca listę rozdzieloną spacjami.

Edycja: zapisano 6 bajtów dzięki bardzo fajnym komentarzom.


całkiem pewne, że potrafiszvar J="";...
kot

Również stany OP w komentarzu, że nie trzeba oddzielić przestrzeń-wyjście, tak 1121i 1 2 1 2to zarówno OK
kot

1
@cat Dzięki, zapisałeś mi 6 bajtów
AstroDan

Dodatkowo masz dodatkowe miejsce} return J;};
kot

Wygląda na to, że musisz using System.Textlub gdzieś tam - import nie jest darmowy.
kot

2

Haskell, 85 bajtów

import Data.ByteString as B
import Data.ByteString.UTF8
(B.length.fromString.pure<$>)

Trochę późno, ale byłoby to krótsze, ponieważmap$...
H.PWiz


1

C, 85 bajtów.

l(unsigned char* c){while(*c){int d=(*c>>4)-11;
d=d<0?1:d+(d==1);putchar(48+d);c+=d;}}

Bada wysokie 4 bity każdego bajtu, aby określić kodowanie i liczbę kolejnych bajtów do pominięcia;


Czy to działa na bajty zerowe?
kot

Tak, while *c wyjścia na pusty ciąg znaków, a `c + = d 'pomija nulls w środku wielobajtowego punktu kodowego.
AShelly

1
To jest niepoprawne Koniec łańcucha ( char*naprawdę) w C jest oznaczony bajtem zerowym. Niemożliwe jest odróżnienie bajtów zerowych od rzeczywistego końca łańcucha.
Dennis

@Dennis Właśnie dlatego, że nie ma różnicy :)
kot

1
OP stwierdził w komentarzu (i jest teraz w poście), że możesz zażądać argumentu długości ciągu w bajtach jako argumentu, więc zrób to, a to znów będzie ważne
cat

1

Współczynnik, 57 87 82 80 bajtów

[ [ dup zero? [ drop "1"] [ >bin length 4 /i 10 >base ] if ] { } map-as ""join ]

Wyjaśnił:

USING: kernel math math.parser sequences ;
IN: byte-counts

: string>byte-counts ( str -- counts )
  [                  ! new quotation: takes a char as a fixnum
    dup zero?        ! true if this is a NUL byte
    [ drop "1" ]     ! NUL bytes have length 1
    [ >bin           ! else, convert to binary string
      length         ! length of binary string
      4              ! the constant 4
      /i             ! integer division
      number>string  ! 4 -> "4"
    ] if             ! conditionally execute one of the previous quotations
  ]                  ! end
  { } map-as         ! map and clone-like an { } array
  "" join ;          ! join array of 1strings on empty string

Testy jednostkowe:

USING: tools.test byte-counts ;
IN: byte-counts.tests

{ "1" } [ "!" string>byte-counts ] unit-test
{ "1111" } [ "Ciao" string>byte-counts ] unit-test
{ "1212"} [ "tʃaʊ" string>byte-counts ] unit-test
{ "1121" } [ "Adám" string>byte-counts ] unit-test
{ "212" } [ "ĉaŭ" string>byte-counts ] unit-test
{ "12112" } [ "ĉaŭ" string>byte-counts ] unit-test
{ "333" } [ "チャオ" string>byte-counts ] unit-test
{ "" } [ "" string>byte-counts ] unit-test
{ "1234" } [ "!±≡𩸽" string>byte-counts ] unit-test
{ "1" } [ "\0" string>byte-counts ] unit-test

Teraz wszyscy przechodzą. do:


1

Swift 2.2, 67 52 50 bajtów

for c in i.characters{print(String(c).utf8.count)}

Okropnie brzydka. Nie ma sposobu, aby uzyskać długość UTF-8 postaci w Swift, więc muszę iterować ciąg po znaku, przekonwertować na Charactera Stringi znaleźć counttę 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 countzamiast underestimateCount().

Rewizje 2: Zapisano kolejne 2 znaki, używając pętli for-in zamiast a dla każdego zamknięcia.


1

Rdza, 53 bajty

|s:&str|for c in s.chars(){print!("{}",c.len_utf8())}

Rdza ma prymitywy znaków utf-8, iteratory i lambdy, więc było to proste. Kod testowy:

fn main() {
    let s = "Löwe 老虎 Léopard💖💖💖💖";
    let f =|s:&str|for c in s.chars(){print!("{}",c.len_utf8())};
    f(s);
}

Wyjścia

1211133112111114444 

1

jq, 26 znaków

(23-znakowy kod + 3-znakowa opcja wiersza poleceń)

(./"")[]|utf8bytelength

Mam nadzieję, że konkuruje. Chociaż utf8bytelengthzostał dodany 9 ++ miesięcy przed tym pytaniem, to nie jest jeszcze uwzględnione w wersji wydany.

Przykładowy przebieg:

bash-4.3$ ./jq -R '(./"")[]|utf8bytelength' <<< 'tʃaʊ'
1
2
1
2

bash-4.3$ ./jq -R '(./"")[]|utf8bytelength' <<< 'ĉaŭ '
1
2
1
1
2
1

bash-4.3$ ./jq -R '(./"")[]|utf8bytelength' <<< 'チャオ'
3
3
3

bash-4.3$ ./jq -R '(./"")[]|utf8bytelength' <<< ''

bash-4.3$ ./jq -R '(./"")[]|utf8bytelength' <<< '!±≡𩸽'
1
2
3
4


1

SmileBASIC, 69 bajtów

DEF C B
WHILE I<LEN(B)Q=INSTR(BIN$(B[I],8),"0")I=I+Q+!Q?Q+!Q
WEND
END

Dane wejściowe to tablica bajtów.

Liczba bajtów w znaku UTF-8 jest równa liczbie 1bitów wiodących w pierwszym bajcie (chyba że nie ma żadnych 1znaków, w którym to przypadku jest to 1 bajt). Aby znaleźć liczbę wiodących 1, program znajduje pierwszy 0w reprezentacji binarnej, a następnie dodaje 1, jeśli było to 0.

0xxxxxxx - no leading ones, 1 byte
110xxxxx 10xxxxxx - 2 leading ones, 2 bytes
1110xxxx 10xxxxxx 10xxxxxx - 3 leading ones, 3 bytes
etc.

1

F #, 59 54 66 bajtów

(s)=seq{for c in s->System.Text.Encoding.UTF8.GetByteCount([|c|])}

Technicznie 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.


1) Odpowiedź Powerhell Timmy'ego D ma ten sam problem 6 bajtów na kanji. Przypisałbym to, że Windows jest głupi i bezużyteczny w Unicode. 2) Jeśli otrzymujesz 6 bajtów dla kanji podczas odczytu z pliku przywołanego, UTF-8 without BOMto 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|])}.
kot

Dostaję też, error FS0039: The namespace or module 'Encoding' is not definedgdy próbuję to uruchomić. Co ja robię źle?
kot

Witamy również w Programowaniu łamigłówek i Code Golf, to jest dobra pierwsza odpowiedź! : D
cat

@cat Musisz otworzyć System.Textprzestrzeń nazw. Zakładam, że przestrzeń nazw otwiera się i kod dostępu jest uwzględniony, pochodzący z odpowiedzi C # AstroDan.
uszczelniony interfejs

Trzeba liczyć bajtów każdy import, #include, open, load, require, using, USING:etc tutaj na PPCG. Odpowiedź C # AstroDana jest podobnie błędna i powiadomiłem ich o tym.
kot

1

05AB1E , 15 bajtów

ÇεDžy‹i1ë.²<5÷>

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:

Ç                   # Convert each character to its unicode value
 εD                 # Foreach over this list
      i             #  If the current item
     ‹              #  is smaller than
   žy               #  128
       1            #   Use 1
        ë           #  Else
         .²         #   Use log_2
           <        #   minus 1
            5÷      #   integer-divided by 5
              >     #   plus 1

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:

if(unicodeValue < 128)
  return 1
else
  return log_2(unicodeValue-1)//5+1    # (where // is integer-division)

Zainspirowany odpowiedzią Python 3 na TheBikingViking .


0

Zsh , 41 bajtów

for c (${(s::)1})set +o multibyte&&<<<$#c

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.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.