Bytes / Personagem


28

Tarefa

Dada uma string UTF-8 (por qualquer meio), responda (por qualquer meio) uma lista equivalente em que cada elemento é o número de bytes usados ​​para codificar o caractere de entrada correspondente.

Exemplos

!1

Ciao1 1 1 1

tʃaʊ1 2 1 2

Adám1 1 2 1

ĉaŭ2 1 2(caracteres únicos)

ĉaŭ1 2 1 1 2(usa combinações de sobreposições)

チャオ3 3 3

(entrada vazia) → (saída vazia)

!±≡𩸽1 2 3 4

(um byte nulo) → 1

Bytes nulos

Se a única maneira de continuar lendo a entrada além de bytes nulos é conhecendo a contagem total de bytes, você poderá obtê-la por qualquer meio (inclusive a entrada do usuário).

Se seu idioma não puder manipular bytes nulos, você poderá assumir que a entrada não contém nulos.


1
Se a entrada estiver vazia, podemos gerar 0 ou outro valor falsey?
Alex A.

2
Posso imprimir a contagem de bytes sem separação? O valor mais alto possível é 6, por isso é inequívoco.
Dennis

3
Temos que suportar bytes nulos? Aqueles pode ser uma verdadeira dor em algumas línguas ...
Dennis

3
Você deve adicionar isso à postagem. Não conheço a maioria dos idiomas o suficiente para saber se isso faz diferença, mas acho que isso invalida pelo menos duas das respostas.
Dennis

2
@ Adám sim, será. Em C, por exemplo, as seqüências de caracteres C terminam com um byte NUL, então você para de ler assim que encontrar um. Se você souber o comprimento da string, parará de ler depois de tantos bytes, NUL e tudo.
cat

Respostas:


10

Pitão, 9 7 bytes

Obrigado a @Maltysen por salvar 2 bytes!

mlc.Bd8

Suíte de teste

Converte todos os caracteres da entrada na sua representação binária e, em seguida, divide-os em pedaços de comprimento 8. O número desses pedaços é a quantidade de bytes necessários para codificar esse caractere.


1
você pode salvar 2 bytes dividindo em vez de dividir e removendo o .E pyth.herokuapp.com/…
Maltysen

@ Maltysen Isso é inteligente, obrigado!
Denker

1
Resposta comprimento mesmo que se baseia em um truque semelhante:mlhc8.B
FryAmTheEggman

@LeakyNun, então seria simples dar um caso de teste que falha, não é?
Lause

Para salvar outro byte, em vez de dividir em partes de 8, use cada 8: ml%8.B (agora destá implícito).
Anders Kaseorg


11

C, 68 65 bytes

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

Graças a @FryAmTheEggman por jogar fora 3 bytes!

Teste em Ideone .


11

APL, 15 caracteres

≢¨'UTF-8'∘⎕ucs¨

Em inglês: converta cada caractere em UTF-8 (ou seja: representação do vetor de bytes) e obtenha sua contagem.


Salvar um byte:≢¨'UTF-8'∘⎕ucs¨
Adám 23/06/16

De fato @ Adám ... Saúde.
lstefano 23/06

Uma abordagem interessante (mas mais longa) baseada em array:+⌿0 7 11 16∘.≤2⍟⎕UCS
Adám

Versão 16.0:0 7 11 16⍸2⍟⎕UCS
Adám

7

GolfScript, 16 bytes

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

Experimente online!

fundo

GolfScript não tem idéia do que é Unicode; todas as strings (entrada, saída, interna) são compostas de bytes. Embora isso possa ser muito chato, é perfeito para esse desafio.

UTF-8 codifica caracteres ASCII e não ASCII de maneira diferente:

  • Todos os pontos de código abaixo de 128 são codificados como 0xxxxxxx .

  • Todos os outros pontos de código são codificados como 11xxxxxx 10xxxxxx ... 10xxxxxx .

Isso significa que a codificação de cada caractere Unicode contém um único 0xxxxxxxbyte ou um único11xxxxxx byte e 1 a 5 10xxxxxxbytes.

Ao dividir todos os bytes da entrada por 64 , transformamos 0xxxxxxxem 0 ou 1 , 11xxxxxxem 3 e 10xxxxxxem 2 .

Se compararmos o quociente com 2 - pressionar 1 por 2 ; e 0 para 0 , 1 e 3 - cada caractere será transformado em 0 , seguido de 1 a 5 1 's.

Tudo o que resta é dividir a sequência resultante nas ocorrências de 0 , contar o número de1's between those zeroes and add one to the amount.

Como funciona

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

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

NB

OK, isso deve funcionar e funciona em quase todos os casos de teste, exceto os 𩸽que, de alguma forma, são contados como 3,3na minha máquina. Esse personagem até mostra como7 bytes on my computer. I suspect this is due to some sort of bug in the Windows or .NET version that I'm running locally, as @Mego doesn't have that issue. (Edit: @cat points out this is due to BOM. Thanks for solving that mystery, @cat!)

No entanto, isso ainda não explica todo o problema. Acho que sei de onde vêm alguns dos problemas. Dentro do .NET, todas as seqüências são compostas de unidades de código UTF-16 (que é o tipo System.Char). Com a conversão de texto muito flexível que o PowerShell usa, há muitas projeções e conversões implícitas entre os tipos em segundo plano. Provavelmente, esse é um fator que contribui para o comportamento que estamos vendo - por exemplo, [system.text.encoding]::utf8.getchars([System.Text.UTF8Encoding]::UTF8.GetBytes('𩸽'))retorna dois não imprimíveis, em vez de um único caractere.


Explicação

Código muito simples. Pega a entrada $args[0]e a lança explicitamente como um array de caracteres, para que possamos percorrer cada componente da string |%{...}. A cada iteração, usamos a chamada .NET [System.Text.Encoding]::UTF8.GetByteCount()(o System.implícito) para obter a contagem de bytes do caractere atual $_. Isso é colocado no pipeline para saída posterior. Uma vez que é uma coleção de[int] s retornada, a conversão para uma matriz está implícita.

Execuções de teste

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

Editado para adicionar Isso explica adequadamente o requisito de bytes nulos que foi adicionado ao desafio depois que eu postei originalmente, desde que você extraia os dados de um arquivo de texto e os canalize da seguinte maneira:

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.Sim, isso é devido à marca de ordem de bytes, que é o que você obtém no Windows com UTF-8. Diga ao Notepad ++ para usar UTF-8 without BOM(como você sempre deve evitar a BOM , especialmente para compatibilidade com Unicies) e você encontrará que o arquivo tem um tamanho de 4 bytes, porque a BOM é 3 e 4 + 3 = 7
cat

@cat Ah, sim, isso faz sentido. OK, então isso explica a diferença no tamanho dos arquivos. No entanto, isso ainda não explica o comportamento diferente dentro do próprio shell. Por exemplo, salvá-lo como UTF-8 sem BOM e a execução get-content -Encoding UTF8 .\z.txt|%{.\bytes-per-character.ps1 $_}ainda retornam 3,3.
AdmBorkBork



6

JavaScript (ES6), 54 45 43 bytes

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

Editar: salvou 2 bytes com a ajuda de @ l4m2.


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

@ l4m2 Isso falha para caracteres não BMP, mas eu consegui consertá-lo.
711 Neil


5

Perl 6 ,  77 69  63 bytes

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

Como o Perl 6 usa cadeias NFG, eu tenho que extrair os bytes diretamente, o que evita o recurso.
(NFG é como NFC, exceto que também cria pontos de código compostos sintéticos)

A saída é separada por novas linhas.

Teste:

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)

Explicação:

# 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

Isso funciona porque o primeiro byte em um ponto de código de vários bytes possui o número de bytes codificados dentro dele e os outros bytes no ponto de código têm o bit mais alto definido, mas não o próximo mais alto. Enquanto os pontos de código de byte único não têm o conjunto de bits mais alto.


Não pode fazer read:1e / ou em /while$vez disso? E se isso funcionar if$,?
Erik the Outgolfer

@ EʀɪᴋᴛʜᴇGᴏʟғᴇʀ Não, porque isso seria analisado como algo diferente. Eu posso remover o espaço antes, no whileentanto.
Brad Gilbert b2gills

Você pode explicar as contramedidas do NFG?
JDługosz

Se eu ecoar um byte NUL para o STDIN deste programa, ele será impresso \n1\n1\n, isso é intencional? Basicamente, isso lida com NUL bytes?
cat

@cat Por que não? Quando faço isso: perl -e 'print "𩸽\0𩸽"' | perl6 -e '...'fico 4␤1␤4exatamente como eu esperaria. (A parte sobre nuls foi adicionada depois que eu postei)
Brad Gilbert b2gills

5

Python 3, 82 bytes

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

Isso é muito mais longo que a outra resposta do Python e a maioria das outras respostas, mas usa uma abordagem que envolve logaritmos que eu ainda não vi.

Uma função anônima que recebe entrada, via argumento, como uma sequência e retorna uma lista.

Experimente no Ideone

Como funciona

Esse método depende da maneira como o UTF-8 codifica o ponto de código de um caractere. Se o ponto de código for menor que 128, o caractere será codificado como em ASCII:

0xxxxxxx

Onde x representa os bits do ponto de código. No entanto, para pontos de código maiores ou iguais a 128, o primeiro byte é preenchido com o mesmo número de 1s que o número total de bytes e os bytes subsequentes são iniciados 10. Os bits do ponto de código são então inseridos para fornecer a menor seqüência multibyte possível e os bits restantes se tornam 0.

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

e assim por diante.

Agora, pode-se notar que, para cada número de bytes n, o limite superior para o número de bits do ponto de código é dado por(-n+7)+6(n-1) = 5n+1 . Portanto, o ponto de código limite superior cpara cada um né dado, em decimal, por c= 2^(5n+1). Reorganizar isso dán = (log2(c)-1)/5 . Portanto, para qualquer ponto de código, o número de bytes pode ser encontrado avaliando a expressão acima e, em seguida, assumindo o teto.

No entanto, isso não funciona para pontos de código no intervalo 64 <= c <= 127, pois a falta de um preenchimento1 devido à codificação semelhante a ASCII para caracteres de 1 byte significa que o limite superior incorreto é previsto e log2indefinido c = 0, o que acontece se um byte nulo está presente na entrada. Portanto, se c <= 127um valor de1 for retornado para n.

É exatamente isso que o código está fazendo; para cada caractere ina seqüência de caracteres x, o ponto de código é encontrado usando a ordfunção e o teto da expressão é encontrado usando a divisão de números inteiros em vez da flutuação 5e adicionando 1. Como o tipo float do Python sempre representa números inteiros x.0, mesmo após a divisão do número inteiro, o resultado é passado para a intfunção para remover o zero à direita. Se ord(i) <= 127, um curto-circuito lógico significa que 1é retornado. O número de bytes para cada caractere é armazenado como um elemento em uma lista e essa lista é retornada.


5

Java 10, 100 96 95 67 61 bytes

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

-4 bytes removendo espaços porque isso é permitido nos comentários
-1 byte, mudando UTF-8para utf8
-28 bytes, passando de Java 7 para 8 (em a->{...}vez de void c(char[]i)throws Exception{...})
-3 bytes, recebendo a entrada como String-array em vez de character-array, e
-3 bytes indo do Java 8 para o 10 (em varvez de String)

Explicação:

Experimente 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

Funciona para bytes nulos?
cat

@cat O caso de teste para bytes nulos foi adicionado posteriormente. Mas sim, ele também funciona para bytes nulos e eu adicionei o caso de teste.
Kevin Cruijssen

3

Julia, 34 bytes

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

Esta é uma função anônima que aceita uma string e retorna uma matriz inteira. Para chamá-lo, atribua-o a uma variável.

A abordagem é bastante direta: se a entrada estiver vazia, a saída estará vazia. Caso contrário, mapeamos osizeof função, que conta o número de bytes em uma string, para cada substring de um caractere.

Experimente online! (inclui todos os casos de teste)


s->[sizeof("$c")for c=s]salva alguns bytes.
Dennis

Ímpar; se split("","")não voltar []? (JavaScript "".split("")faz.) #
305 Neil

@ Neil split("","")parece dar ""(ao contrário do Python, que dá uma exceção), mas eu não sei nada sobre a compatibilidade []e ""na julia.
cat

@ Neil Não, split("", "") == [""]ou seja, uma matriz de um elemento contendo uma string vazia, mas o problema é o sizeof("") == 0que o OP disse que não é permitido.
Alex A.

@ Dennis Isso falhará em strings não indexáveis. (Não consigo pensar em um exemplo de antemão.) #
Alex A.

3

PHP, 92 57 bytes

Pensando bem, você pode fazer isso com muito menos folga:

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

Experimente on-line, observe que isso é um pouco mais longo, pois usa stdin em vez de um argumento de programa.
Esta versão requer que você ignore os avisos enviados ao stderr, mas tudo bem .

versão antiga:
usa uma abordagem bastante diferente da outra resposta php. Baseia-se na falta de suporte nativo para strings de vários bytes no php.

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

Boa resposta! Eu acho que você pode soltar completamente a tag de abertura ou alterá-la para #<?=
cat

Sem a tag, é um trecho de código em vez de um programa, e mesmo que seja permitido, me sinto vagamente sujo. Com a tag alternativa, você recebe um erro de análise (ou pelo menos eu fiz no php 5.5, que é o que estou acostumado).
user55641

Ok :) Eu não sei PHP (nem quero, tosse ), mas eu vou apontá-lo aqui: codegolf.stackexchange.com/questions/2913
cat

3

Emacs Lisp, 55 49 bytes

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

Primeiro disseca a string em uma lista de caracteres com (mapcar 'string s). A stringfunção no Emacs Lisp pega uma lista de caracteres e cria uma string a partir deles. Devido à maneira como o Emacs divide as strings com mapcar(ou seja, em uma lista de números inteiros, não caracteres ou strings), essa conversão explícita é necessária. Em seguida, mapeia a string-bytesfunção para essa lista de cadeias.

Exemplo:

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

Casos de teste:

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

Resposta antiga:

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

Casos de teste:

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


O que acontece com o nilse você achatar o resultado?
Adám 27/06/16

1
@ Adám nilé uma lista vazia (e a única maneira de dizer "falso" no Emacs). Embora não haja um achatamento padrão no Emacs (você pode usar os traços -flatten), qualquer implementação possível o eliminaria.
Lord Yuuma

3

JavaScript (Nó), 27 bytes

s=>s.map(Buffer.byteLength)

Isso recebe a entrada como uma matriz de caracteres individuais e retorna uma matriz de contagens de bytes.

Bufferé um método de representar dados binários brutos. Buffer.byteLength (string) fornece o número de bytes na string. UTF-8 é a codificação padrão. Observe que apenas o Node.js possui buffers, não o JS do navegador. O equivalente aproximado do navegador é chamado Blob , com 31 bytes:

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

Teste

Salve este arquivo e execute-o através do nó ou tente 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));
});

Este deve ser o resultado:

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

Golfe

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

Algoritmo

string de entrada hexdump, dobre 2 caracteres por linha, corte apenas o primeiro caractere

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

2
c
b
e
8
a
f
a
b
b

(4 bits de ordem superior de cada byte de entrada como um caractere hexadecimal, um por linha)

Remova os "bytes de continuação" 0x80..0xBF

tr -d '89ab'

2
c

e


f

(o que resta, são 4 bits do primeiro byte de cada caractere unicode)

mapear os primeiros bits no comprimento do caractere, recolher a saída e imprimir

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

1 2 3 4

Teste

 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 boa abordagem. Você realmente lê o resultado diretamente da entrada.
Adám 17/11/16

A -topção de trnão me era familiar e aparentemente é uma extensão do GNU. A canalização para a substituição de comando depois echotambém pode valer uma explicação um pouco mais detalhada.
Tripleee


2

C #, 89 82 bytes

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

Um lambda C # simples que itera pela string e retorna a lista separada por espaço.

Editar: salvou 6 bytes graças a alguns comentários muito legais.


certeza que você pode fazervar J="";...
cat

Além disso, os estados do OP em um comentário que você não precisa de espaço-separar a saída para 1121e 1 2 1 2são ambos OK
cat

1
@cat Obrigado, me salvou 6 bytes
AstroDan

Além disso, você tem um espaço extra em} return J;};
cat

Parece que você precisa using System.Textou mais ou menos - as importações não são gratuitas.
cat

2

Haskell, 85 bytes

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

Um pouco tarde, mas isso seria mais curto quantomap$...
H.PWiz


1

C, 85 bytes.

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

Examina os 4 bits mais altos de cada byte para determinar a codificação e o número de bytes subsequentes a serem ignorados;


Isso funciona em bytes nulos?
cat

Sim, as while *c saídas em uma string vazia e o `c + = d 'ignoram nulos no meio de um ponto de código de vários bytes.
AShelly

1
Isso está incorreto. O final de uma string ( char*, realmente) em C é marcado com um byte nulo. É impossível distinguir bytes nulos do final real da string.
Dennis

@Dennis Precisamente porque não há diferença :) #
cat

1
O OP declarou em um comentário (e é agora no post) que você pode solicitar o comprimento da corda em bytes como argumento, então fazer isso e isso será válido novamente
cat

1

Fator, 57 87 82 80 bytes

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

Explicado:

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

Testes unitários:

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

Todos eles passam agora. c:


1

Swift 2.2, 67 52 50 bytes

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

Horrivelmente feio. Não há como obter o comprimento UTF-8 de um personagem no Swift, portanto, eu preciso percorrer a sequência de caracteres por caractere, converter o Characterem um Stringe encontrar o countcaractere único.String (ei, pelo menos, há um método para fazer isso). Procurando otimizações, possivelmente usando um scanner.

Revisão 1: salvou 15 bytes usando em countvez de underestimateCount().

Revisões 2: salvou outro caractere 2 usando um loop for-in em vez de um para cada fechamento.


1

Ferrugem, 53 bytes

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

Rust possui utf-8 char primitives, iteradores e lambdas, portanto isso foi direto. Código do teste:

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

Saídas

1211133112111114444 

1

jq, 26 caracteres

(Código de 23 caracteres + opção de linha de comando de 3 caracteres)

(./"")[]|utf8bytelength

Espero competir. Embora tenha utf8bytelengthsido adicionado 9 ++ meses antes desta pergunta, ainda não está incluído na versão lançada.

Exemplo de execução:

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 bytes

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

Entrada é uma matriz de bytes.

O número de bytes em um caractere UTF-8 é igual ao número de 1bits iniciais no primeiro byte (a menos que não haja 1s, nesse caso, o caractere é de 1 byte). Para encontrar o número de 1s iniciais, o programa encontra o primeiro 0na representação binária e adiciona 1 se esse for 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 bytes

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

Tecnicamente, s é uma sequência de caracteres, mas acontece que há uma conversão implícita que permite que uma string seja passada.

Ao testar isso no console !±≡𩸽, ele divide o kanji em dois caracteres, cada um com 3 bytes de comprimento. Todos os outros casos de teste funcionam bem.

Edit: Acontece que importações comuns de namespace não estão implícitas. Até mais 12 caracteres.


1) A resposta do Timmy D ao powershell tem o mesmo problema de 6 bytes por kanji. Eu atribuiria isso ao Windows ser burro e inútil no Unicode. 2) Se você obtiver 6 bytes para o kanji ao ler um arquivo habilitado UTF-8 without BOM, isso está errado e deve ser corrigido. 3) Parece que o F # precisa de instruções como let f(x)= ...terminar ;;, como SML. 4) Você pode deixar de atribuir um nome a esta função anônima, ou seja (s)=seq{for c in s->Encoding.UTF8.GetByteCount([|c|])}.
cat

Além disso, recebo error FS0039: The namespace or module 'Encoding' is not definedao tentar executar isso. O que estou fazendo errado?
cat

Além disso, seja bem-vindo à programação de quebra-cabeças e código de golfe, esta é uma ótima primeira resposta! : D
cat

@cat Você precisa abrir o System.Textespaço para nome. Estou assumindo que o espaço para nome é aberto e o código de entrada está incluído, vindo da resposta C # do AstroDan.
interface selada

Você precisa contar os bytes de qualquer import, #include, open, load, require, using, USING:etc aqui na PPCG. A resposta C # do AstroDan é igualmente errônea, e eu os informei disso.
cat

1

05AB1E , 15 bytes

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

Experimente online.
Cabeçalhoεé usado para cada um sobre todos os casos de teste;
Rodapéï]J]»para imprimir bem as listas de caracteres de saída (ï: decimais e caracteres para números inteiros;:]fechar if-else e para-eachJ;: unir dígitos juntos};: fechar cabeçalho foreach;:unir»por novas linhas).

Explicação:

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

Como o 05AB1E não possui nenhum built-in para converter caracteres na quantidade de bytes usados, eu uso Çpara converter os caracteres em seus valores unicode e, em cada um, faça o seguinte em pseudo-código:

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

Inspirado na resposta Python 3 de @TheBikingViking .


0

Zsh , 41 bytes

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

Experimente online!

Como o Zsh reconhece UTF-8, dividimos a sequência em caracteres, desativamos o multibyte e imprimimos o comprimento de cada caractere.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.