Byte / Carattere


28

Compito

Data una stringa UTF-8 (in ogni caso) risponde (con qualsiasi mezzo) un elenco equivalente in cui ogni elemento è il numero di byte utilizzati per codificare il carattere di input corrispondente.

Esempi

!1

Ciao1 1 1 1

tʃaʊ1 2 1 2

Adám1 1 2 1

ĉaŭ2 1 2(caratteri singoli)

ĉaŭ1 2 1 1 2(utilizza combinazioni di sovrapposizioni)

チャオ3 3 3

(input vuoto) → (output vuoto)

!±≡𩸽1 2 3 4

(Un byte null) → 1

Byte nulli

Se l'unico modo per continuare a leggere l'input oltre i byte nulli è conoscere il conteggio totale dei byte, è possibile ottenere il conteggio dei byte in qualsiasi modo (anche l'input dell'utente).

Se la tua lingua non è in grado di gestire byte null, puoi supporre che l'input non contenga null.


1
Se l'ingresso è vuoto, possiamo emettere 0 o un altro valore di falso?
Alex A.

2
Posso stampare il numero di byte senza separazione? Il valore più alto possibile è 6, quindi non è ambiguo.
Dennis,

3
Dobbiamo supportare byte null? Questi possono essere un vero dolore in alcune lingue ...
Dennis,

3
Dovresti aggiungerlo al post. Non conosco la maggior parte delle lingue abbastanza bene da dire se fa la differenza, ma penso che invalidi almeno due delle risposte.
Dennis,

2
@ Adám sì. In C, ad esempio, le stringhe C terminano con un byte NUL, quindi smetti di leggere non appena ne trovi uno. Se conosci la lunghezza della stringa, smetti di leggere dopo tanti byte, NUL e tutti.
cat

Risposte:


10

Pyth, 9 7 byte

Grazie a @Maltysen per aver salvato 2 byte!

mlc.Bd8

Suite di test

Converte ogni carattere dell'input nella sua rappresentazione binaria e quindi lo divide in blocchi di lunghezza 8. Il numero di quei blocchi è quindi la quantità di byte necessari per codificare quel carattere.


1
puoi salvare 2 byte con la suddivisione invece di dividere e quindi rimuovere .E pyth.herokuapp.com/…
Maltysen il

@Maltysen È intelligente, grazie!
Denker,

1
Stessa risposta che si basa su un trucco simile:mlhc8.B
FryAmTheEggman,

@LeakyNun allora sarebbe semplice dare un caso di prova che fallisce, no?
Lause

Per salvare un altro byte, anziché dividerlo in blocchi di 8, prendi ogni 8: ml%8.B(ora dè implicito).
Anders Kaseorg,


11

C, 68 65 byte

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

Grazie a @FryAmTheEggman per giocare a golf con 3 byte!

Provalo su Ideone .


11

APL, 15 caratteri

≢¨'UTF-8'∘⎕ucs¨

In inglese: converti ogni personaggio in UTF-8 (che significa: vettore di rappresentazione dei byte) e ottieni il riscontro.


Salvare un byte:≢¨'UTF-8'∘⎕ucs¨
Adám,

Infatti @ Adám ... Saluti.
lstefano,

Un approccio interessante (ma più lungo) basato su array:+⌿0 7 11 16∘.≤2⍟⎕UCS
Adám,

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

7

GolfScript, 16 byte

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

Provalo online!

sfondo

GolfScript non ha idea di cosa sia Unicode; tutte le stringhe (input, output, internal) sono composte da byte. Anche se può essere piuttosto fastidioso, è perfetto per questa sfida.

UTF-8 codifica i caratteri ASCII e non ASCII in modo diverso:

  • Tutti i punti di codice inferiori a 128 sono codificati come 0xxxxxxx.

  • Tutti gli altri punti di codice sono codificati come 11xxxxxx 10xxxxxx ... 10xxxxxx.

Ciò significa che la codifica di ciascun carattere Unicode contiene un singolo 0xxxxxxxbyte o un singolo 11xxxxxxbyte e da 1 a 5 10xxxxxxbyte.

Dividendo tutti i byte dell'input per 64 , trasformiamo 0xxxxxxxin 0 o 1 , 11xxxxxxin 3 e 10xxxxxxin 2 .

Se confrontiamo il quoziente con 2 - spingendo 1 per 2 ; e 0 per 0 , 1 e 3 - ogni personaggio verrà trasformato in 0 , seguito da 1 a 5 1 's.

Non resta che dividere la stringa risultante in occorrenze di 0 , contare il numero di 1 tra questi zero e aggiungerne uno alla quantità.

Come funziona

{     }%          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 byte

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

NB

OK, questo dovrebbe funzionare e funziona in quasi tutti i casi di test, tranne per il fatto 𩸽che è in qualche modo contato come 3,3sulla mia macchina. Quel personaggio mostra anche come 7 byte sul mio computer. Sospetto che ciò sia dovuto a una specie di bug nella versione Windows o .NET che sto eseguendo localmente, poiché @Mego non ha questo problema . ( Modifica: @cat sottolinea che ciò è dovuto alla DBA . Grazie per aver risolto quel mistero, @cat! )

Tuttavia, ciò non rappresenta ancora tutto il problema. Penso di sapere da dove provengono alcuni dei problemi. All'interno di .NET, tutte le stringhe sono composte da unità di codice UTF-16 (che è il tipo System.Char). Con il typecasting molto diffuso che PowerShell utilizza, c'è un sacco di casting e conversione impliciti tra i tipi in background. Probabilmente questo è un fattore che contribuisce al comportamento che stiamo vedendo - ad esempio, [system.text.encoding]::utf8.getchars([System.Text.UTF8Encoding]::UTF8.GetBytes('𩸽'))restituisce due non stampabili, piuttosto che un singolo personaggio.


Spiegazione

Codice molto semplice. Accetta l'input $args[0]e lo lancia esplicitamente come un array di caratteri in modo da poter eseguire il ciclo attraverso ogni componente della stringa |%{...}. Ogni iterazione, usiamo la chiamata .NET [System.Text.Encoding]::UTF8.GetByteCount()( System.è implicita) per ottenere il conteggio dei byte del carattere corrente $_. Viene inserito nella pipeline per l'output successivo. Poiché si tratta di una raccolta di [int]s restituiti, è implicito il cast su un array.

Esecuzioni di test

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

Modificato per aggiungere Ciò tiene correttamente conto del requisito di byte nulli che è stato aggiunto alla sfida dopo che ho pubblicato inizialmente, a condizione che si estraggano i dati da un file di testo e lo si installi come segue:

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.Sì, è grazie al Byte-Order Mark che è quello che ottieni su Windows con UTF-8. Di 'a Notepad ++ di usare UTF-8 without BOM(come dovresti sempre evitare la DBA , specialmente per compatibilità con Unicies) e scoprirai che il file ha una dimensione di 4 byte, perché la DBA è 3 e 4 + 3 = 7
cat

@cat Ah, sì, ha senso. OK, in modo tale da tenere conto della differenza nelle dimensioni dei file. Tuttavia, ciò non tiene conto del diverso comportamento all'interno della shell stessa. Ad esempio, salvandolo come UTF-8 senza BOM e l'esecuzione get-content -Encoding UTF8 .\z.txt|%{.\bytes-per-character.ps1 $_}continua a restituire 3,3.
AdmBorkBork,



6

JavaScript (ES6), 54 45 43 byte

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

Modifica: salvato 2 byte con l'aiuto di @ l4m2.


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

@ l4m2 Questo non funziona per i personaggi non BMP ma sono stato in grado di risolverlo.
Neil


5

Perl 6 ,  77 69  63 byte

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

Dato che Perl 6 utilizza stringhe NFG, devo inserire direttamente i byte, il che elude la funzione.
(NFG è come NFC tranne che crea anche punti di codice composti sintetici)

L'output è separato da newline.

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)

Spiegazione:

# 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

Questo funziona perché il primo byte in un punto di codice multi-byte ha il numero di byte codificati al suo interno e gli altri byte nel punto di codice hanno il bit più alto impostato, ma non il successivo più alto. Mentre i punti di codice a byte singolo non hanno il bit più alto impostato.


Non puoi fare read:1e / o /while$invece? E se funziona if$,?
Erik the Outgolfer,

@ EʀɪᴋᴛʜᴇGᴏʟғᴇʀ No perché sarebbe analizzato come qualcosa di diverso. Posso rimuovere lo spazio prima whileperò.
Brad Gilbert b2gills il

Puoi spiegare le contromisure NFG?
JDługosz,

Se echo un byte NUL sullo STDIN di questo programma, viene stampato \n1\n1\n, è intenzionale? Fondamentalmente, questo gestisce byte NUL?
gatto,

@cat Perché non dovrebbe? Quando faccio questo: perl -e 'print "𩸽\0𩸽"' | perl6 -e '...'ottengo 4␤1␤4proprio come mi aspetterei. (La parte su nuls è stata aggiunta dopo che ho pubblicato però)
Brad Gilbert b2gills

5

Python 3, 82 byte

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

Questo è molto più lungo dell'altra risposta di Python e della maggior parte delle altre risposte, ma utilizza un approccio che coinvolge logaritmi che non ho ancora visto.

Una funzione anonima che accetta input, tramite argomento, come stringa e restituisce un elenco.

Provalo su Ideone

Come funziona

Questo metodo si basa sul modo in cui UTF-8 codifica il punto di codice di un carattere. Se il punto di codice è inferiore a 128, il carattere è codificato come in ASCII:

0xxxxxxx

dove xrappresenta i bit del punto di codice. Tuttavia, per i punti di codice maggiori o uguali a 128, il primo byte viene riempito con lo stesso numero di 1s del numero totale di byte e iniziano i byte successivi 10. I bit del punto di codice vengono quindi immessi per fornire la sequenza multibyte più breve possibile e tutti i bit rimanenti diventano 0.

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

e così via.

Ora si può notare che per ogni numero di byte n, viene dato il limite superiore per il numero di bit del punto di codice (-n+7)+6(n-1) = 5n+1. Quindi, il punto di codice limite superiore cper ciascuno nè dato, in decimale, da c= 2^(5n+1). Riorganizzare questo dà n = (log2(c)-1)/5. Pertanto, per qualsiasi punto di codice, è possibile trovare il numero di byte valutando l'espressione precedente e quindi prendendo il soffitto.

Tuttavia, ciò non funziona per i punti di codice nell'intervallo 64 <= c <= 127, poiché la mancanza di un padding a 1causa della codifica simile a ASCII per i caratteri a 1 byte significa che è previsto un limite superiore errato, e log2non è definito per c = 0, che si verifica se un byte null è presente nell'input. Pertanto, se c <= 127, 1viene restituito un valore di per n.

Questo è esattamente ciò che sta facendo il codice; per ogni carattere inella stringa x, il punto di codice viene trovato usando la ordfunzione e il limite dell'espressione viene trovato usando numero intero anziché divisione float 5e quindi aggiungendo 1. Poiché il tipo float di Python rappresenta sempre numeri interi poiché x.0, anche dopo la divisione dei numeri interi, il risultato viene passato alla intfunzione per rimuovere lo zero finale. Se ord(i) <= 127, corto circuito logico significa che 1viene invece restituito. Il numero di byte per ciascun carattere viene archiviato come elemento in un elenco e questo elenco viene restituito.


5

Java 10, 100 96 95 67 61 byte

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

-4 byte rimuovendo gli spazi perché ciò è consentito nei commenti
-1 byte cambiando UTF-8in utf8
-28 byte passando da Java 7 a 8 ( a->{...}anziché void c(char[]i)throws Exception{...})
-3 byte prendendo l'input come array di stringhe anziché array di caratteri e
-3 byte passando da Java 8 a 10 ( varanziché String)

Spiegazione:

Provalo 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

Funziona con byte nulli?
gatto,

@cat È stato successivamente aggiunto il caso di test per byte null. Sì, funziona anche con byte nulli e ho aggiunto il test case.
Kevin Cruijssen,

3

Julia, 34 byte

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

Questa è una funzione anonima che accetta una stringa e restituisce un array intero. Per chiamarlo, assegnarlo a una variabile.

L'approccio è piuttosto semplice: se l'input è vuoto, l'output è vuoto. Altrimenti mappiamo la sizeoffunzione, che conta il numero di byte in una stringa, su ogni sottostringa di un carattere.

Provalo online! (include tutti i casi di test)


s->[sizeof("$c")for c=s]salva qualche byte.
Dennis,

Dispari; non split("","")ritorna []? (JavaScript "".split("")fa.)
Neil

@Neil split("","")sembra dare ""(a differenza di Python che dà un'eccezione) ma non so nulla della compatibilità di []e ""in julia.
gatto,

@Neil No, split("", "") == [""]vale a dire un array a un elemento contenente una stringa vuota, ma il problema è quello sizeof("") == 0, che l'OP ha dichiarato non consentito.
Alex A.

@Dennis Quello fallirà per le stringhe non indicizzabili. (Non riesco a pensare a un esempio con disinvoltura però.)
Alex A.

3

PHP, 92 57 byte

Ripensandoci, puoi farlo con molta meno dissolvenza in giro:

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

Provalo online, nota che questo è leggermente più lungo in quanto utilizza stdin piuttosto che un argomento di programma.
Questa versione richiede di ignorare le notifiche inviate a stderr ma va bene .

vecchia versione:
utilizza un approccio piuttosto diverso rispetto all'altra risposta php. Si basa sulla mancanza di supporto nativo per stringhe multi-byte in php.

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

Bella risposta! Penso che puoi eliminare del tutto il tag di apertura o modificarlo in<?=
cat

Senza il tag è uno snippet di codice piuttosto che un programma, e anche se ciò è permesso, mi fa sentire vagamente sporco. Con il tag alternativo si ottiene un errore di analisi (o almeno l'ho fatto su PHP 5.5 che è quello a cui sono abituato).
user55641

Ok :) Non conosco PHP (né voglio tossire ) ma ti indicherò
cat

3

Emacs Lisp, 55 49 byte

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

Divida innanzitutto la stringa in un elenco di caratteri con (mapcar 'string s). La stringfunzione in Emacs Lisp prende un elenco di caratteri e ne crea una stringa. A causa del modo in cui Emacs divide le stringhe mapcar(ovvero in un elenco di numeri interi, non caratteri o stringhe), è necessaria questa conversione esplicita. Quindi mappa la string-bytesfunzione su quell'elenco di stringhe.

Esempio:

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

Casi test:

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

Vecchia risposta:

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

Ungolfed:

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

Casi test:

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


Cosa succede nilse si appiattisce il risultato?
Adám,

1
@Adám nilè un elenco vuoto (e l'unico modo per dire "falso" in Emacs). Sebbene non vi sia alcun appiattimento standard in Emacs (puoi usare i trattini -flatten) ogni possibile implementazione lo eliminerebbe.
Lord Yuuma,

3

JavaScript (nodo), 27 byte

s=>s.map(Buffer.byteLength)

Ciò accetta l'input come una matrice di singoli caratteri e restituisce una matrice di conteggi di byte.

Bufferè un metodo per rappresentare dati binari non elaborati. Buffer.byteLength (stringa) fornisce il numero di byte nella stringa. UTF-8 è la codifica predefinita. Nota che solo Node.js ha buffer, non JS del browser. L'equivalente browser approssimativo si chiama Blob , che arriva a 31 byte:

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

Test

Salvare questo file ed eseguirlo attraverso il nodo o provarlo 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));
});

Questo dovrebbe essere il risultato:

$ 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 byte

golfed

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

Algoritmo

stringa di input hexdump, piega 2 caratteri per riga, taglia solo il primo carattere

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

2
c
b
e
8
a
f
a
b
b

(4 bit di ordine superiore di ogni byte di input come un carattere esadecimale, uno per riga)

Rimuovere i "byte di continuazione" 0x80..0xBF

tr -d '89ab'

2
c

e


f

(ciò che resta sono 4 bit del primo byte di un carattere unicode)

mappare i primi bit nella lunghezza del carattere, comprimere l'output e stampare

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 Bel approccio. In realtà hai letto il risultato direttamente dall'input.
Adám,

L' -topzione per trnon mi era familiare ed è apparentemente un'estensione GNU. Il piping alla sostituzione del comando dopo echopotrebbe anche valere una spiegazione leggermente più dettagliata.
tripleee

2

PHP, 126 byte

<?php $s=fgets(STDIN);echo $s!=''?implode(' ',array_map(function($x){return strlen($x);},preg_split('/(?<!^)(?!$)/u',$s))):'';

Provalo online!


Puoi iniziare il tuo codice con<?=($s=fgets(STDIN))?
Marco

2

C #, 89 82 byte

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

Una semplice lambda C # che scorre la stringa e restituisce l'elenco separato da spazi.

Modifica: salvato 6 byte grazie ad alcuni commenti molto belli.


abbastanza sicuro che puoi farlovar J="";...
cat

Inoltre, in un commento l'OP afferma che non è necessario separare l'output in modo tale 1121che 1 2 1 2siano entrambi OK
cat

1
@cat Grazie, mi ha salvato 6 byte
AstroDan,

Inoltre, hai uno spazio extra in} return J;};
cat

Sembra che tu ne abbia bisogno using System.Texto altro - le importazioni non sono gratuite.
cat

2

Haskell, 85 byte

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

Un po 'in ritardo, ma questo sarebbe più breve dimap$...
H.Pwiz


1

C, 85 byte.

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

Esamina gli alti 4 bit di ciascun byte per determinare la codifica e il numero di byte successivi da saltare;


Funziona su byte null?
gatto,

Sì, while *c esce su una stringa vuota e `c + = d 'salta i valori null nel mezzo di un punto di codice multibyte.
AShelly,

1
Non è corretto La fine di una stringa ( char*, in realtà) in C è contrassegnata da un byte null. È impossibile distinguere i byte null dalla fine effettiva della stringa.
Dennis,

@Dennis Proprio perché non c'è differenza :)
cat

1
L'OP ha dichiarato in un commento (ed è ora nel post) che puoi richiedere la lunghezza della stringa in byte come argomento, quindi fallo e questo sarà di nuovo valido
cat

1

Fattore, 57 87 82 80 byte

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

Ha spiegato:

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

Test unitari:

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

Passano tutti, ora. c:


1

Swift 2.2, 67 52 50 byte

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

Orribilmente brutto. Non c'è modo di ottenere la lunghezza UTF-8 di un personaggio in Swift, quindi ho bisogno di scorrere la stringa per carattere, convertire il carattere Characterin a Stringe trovare il carattere countdi quel singolo carattereString (ehi, almeno c'è un built-in metodo per farlo). Alla ricerca di ottimizzazioni, possibilmente utilizzando uno scanner.

Revisione 1: salvati 15 byte usando countinvece diunderestimateCount() .

Revisioni 2: salvato altri 2 caratteri utilizzando un ciclo for-in anziché un per ogni chiusura.


1

Ruggine, 53 byte

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

La ruggine ha primitivi charf-8, iteratori e lambda, quindi questo è stato semplice. Codice di prova:

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

Uscite

1211133112111114444 

1

jq, 26 caratteri

(Codice 23 caratteri + opzione riga comandi 3 caratteri)

(./"")[]|utf8bytelength

Speriamo di competere. Sebbene sia utf8bytelengthstato aggiunto 9 ++ mesi prima questa domanda, non è ancora incluso nella versione rilasciata.

Esecuzione di esempio:

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 byte

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

L'input è un array di byte.

Il numero di byte in un carattere UTF-8 è uguale al numero di 1bit iniziali nel primo byte (a meno che non ci siano 1s, nel qual caso il carattere è 1 byte). Per trovare il numero di 1 iniziali, il programma trova il primo 0nella rappresentazione binaria, quindi aggiunge 1 se questo era 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 byte

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

Tecnicamente, s è una sequenza di caratteri, ma risulta che esiste una conversione implicita che consente il passaggio di una stringa.

Quando si verifica questo nella console con !±≡𩸽 , divide il kanji in due caratteri, ciascuno lungo 3 byte. Tutti gli altri casi di test funzionano bene.

Modifica: risulta che le importazioni di spazi dei nomi comuni non sono implicite. Altri 12 caratteri.


1) La risposta PowerShell di Timmy D ha lo stesso problema di 6 byte per kanji. Vorrei attribuire a Windows essere stupido e inutile su Unicode. 2) Se ottieni 6 byte per il kanji durante la lettura da un file inserito, UTF-8 without BOMallora questo è sbagliato e dovrebbe essere corretto. 3) Sembra che F # abbia bisogno di affermazioni come let f(x)= ...per finire ;;, come SML. 4) È possibile interrompere l'assegnazione di un nome a questa funzione anonima, ad es (s)=seq{for c in s->Encoding.UTF8.GetByteCount([|c|])}.
gatto,

Inoltre, ottengo error FS0039: The namespace or module 'Encoding' is not definedquando provo a eseguire questo. Che cosa sto facendo di sbagliato?
gatto,

Inoltre, benvenuti a Programming Puzzles e Code Golf, questa è una bella prima risposta! : D
cat

@cat È necessario aprire lo System.Textspazio dei nomi. Suppongo che lo spazio dei nomi si apra e il codice di ingresso sia incluso, proveniente dalla risposta C # di AstroDan.
interfaccia sigillata

È necessario contare i byte di qualsiasi import, #include, open, load, require, using, USING:ecc qui in PPCG. La risposta C # di AstroDan è altrettanto errata, e io li ho notificati.
gatto,

1

05AB1E , 15 byte

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

Provalo online.
L'intestazioneεviene utilizzata per ciascuno dei casi di test;
Pièï]J]»dipaginaper stampare graziosamente gli elenchi di caratteri di output (ï: decimali e caratteri in numeri interi;:]chiudere if-else e per-ciascunoJ;: unire le cifre insieme};: chiudere l'intestazione foreach;» Unire per nuove righe).

Spiegazione:

Ç                   # 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

Dal momento che 05AB1E non ha alcun builtin per convertire i caratteri in quantità di byte utilizzati, io uso Çper convertire i caratteri nei loro valori unicode e in uno per ciascuno eseguo quanto segue in pseudo-codice:

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

Ispirato dalla risposta Python 3 di @TheBikingViking .


0

Zsh , 41 byte

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

Provalo online!

Zsh è a conoscenza di UTF-8, quindi dividiamo la stringa sui caratteri, quindi disabilitiamo il multibyte e stampiamo la lunghezza di ogni carattere.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.