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
Ciao
→ 1 1 1 1
tʃaʊ
→ 1 2 1 2
Adám
→ 1 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.
Respostas:
Pitão,
97 bytesObrigado a @Maltysen por salvar 2 bytes!
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.
fonte
.E
pyth.herokuapp.com/…mlhc8.B
ml%8.B
(agorad
está implícito).Python 3,
4236 bytesfonte
map
.lambda x:map(len,map(str.encode,x))
C,
6865 bytesGraças a @FryAmTheEggman por jogar fora 3 bytes!
Teste em Ideone .
fonte
APL, 15 caracteres
Em inglês: converta cada caractere em UTF-8 (ou seja: representação do vetor de bytes) e obtenha sua contagem.
fonte
≢¨'UTF-8'∘⎕ucs¨
+⌿0 7 11 16∘.≤2⍟⎕UCS
0 7 11 16⍸2⍟⎕UCS
GolfScript, 16 bytes
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
0xxxxxxx
byte ou um único11xxxxxx
byte e 1 a 510xxxxxx
bytes.Ao dividir todos os bytes da entrada por 64 , transformamos
0xxxxxxx
em 0 ou 1 ,11xxxxxx
em 3 e10xxxxxx
em 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
fonte
PowerShell v4, 58 bytes
NB
OK, isso deve funcionar e funciona em quase todos os casos de teste, exceto os
𩸽
que, de alguma forma, são contados como3,3
na 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()
(oSystem.
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
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:
fonte
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 usarUTF-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 = 7get-content -Encoding UTF8 .\z.txt|%{.\bytes-per-character.ps1 $_}
ainda retornam3,3
.-Encoding
parâmetro não parece ser suportado .JavaScript (ES6),
544543 bytesEditar: salvou 2 bytes com a ajuda de @ l4m2.
fonte
s=>[...s].map(c=>encodeURI(c).length/3-4&3)
Ruby, 33 bytes
Mal chega ao Python, sim! Experimente online.
fonte
Perl 6 ,
77 6963 bytesComo 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:
Explicação:
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.
fonte
read:1
e / ou em/while$
vez disso? E se isso funcionarif$
,?while
entanto.\n1\n1\n
, isso é intencional? Basicamente, isso lida com NUL bytes?perl -e 'print "𩸽\0𩸽"' | perl6 -e '...'
fico414
exatamente como eu esperaria. (A parte sobre nuls foi adicionada depois que eu postei)Python 3, 82 bytes
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:
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 de1
s que o número total de bytes e os bytes subsequentes são iniciados10
. 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 tornam0
.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 superiorc
para cada umn
é dado, em decimal, porc= 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 elog2
indefinidoc = 0
, o que acontece se um byte nulo está presente na entrada. Portanto, sec <= 127
um valor de1
for retornado para n.É exatamente isso que o código está fazendo; para cada caractere
i
na seqüência de caracteresx
, o ponto de código é encontrado usando aord
função e o teto da expressão é encontrado usando a divisão de números inteiros em vez da flutuação5
e adicionando1
. Como o tipo float do Python sempre representa números inteirosx.0
, mesmo após a divisão do número inteiro, o resultado é passado para aint
função para remover o zero à direita. Seord(i) <= 127
, um curto-circuito lógico significa que1
é retornado. O número de bytes para cada caractere é armazenado como um elemento em uma lista e essa lista é retornada.fonte
Java 10,
10096956761 bytes-4 bytes removendo espaços porque isso é permitido nos comentários
-1 byte, mudando
UTF-8
parautf8
-28 bytes, passando de Java 7 para 8 (em
a->{...}
vez devoid 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
var
vez deString
)Explicação:
Experimente online.
fonte
Julia, 34 bytes
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 o
sizeof
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)
fonte
s->[sizeof("$c")for c=s]
salva alguns bytes.split("","")
não voltar[]
? (JavaScript"".split("")
faz.) #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.split("", "") == [""]
ou seja, uma matriz de um elemento contendo uma string vazia, mas o problema é osizeof("") == 0
que o OP disse que não é permitido.PHP,
9257 bytesPensando bem, você pode fazer isso com muito menos folga:
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.
fonte
<?=
Emacs Lisp,
5549 bytesPrimeiro disseca a string em uma lista de caracteres com
(mapcar 'string s)
. Astring
função no Emacs Lisp pega uma lista de caracteres e cria uma string a partir deles. Devido à maneira como o Emacs divide as strings commapcar
(ou seja, em uma lista de números inteiros, não caracteres ou strings), essa conversão explícita é necessária. Em seguida, mapeia astring-bytes
função para essa lista de cadeias.Exemplo:
Casos de teste:
Resposta antiga:Ungolfed:
Casos de teste:
fonte
nil
se você achatar o resultado?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.JavaScript (Nó), 27 bytes
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:Teste
Salve este arquivo e execute-o através do nó ou tente online .
Este deve ser o resultado:
fonte
Bash, 74 bytes
Golfe
Algoritmo
string de entrada hexdump, dobre 2 caracteres por linha, corte apenas o primeiro caractere
(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
(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
Teste
fonte
-t
opção detr
não me era familiar e aparentemente é uma extensão do GNU. A canalização para a substituição de comando depoisecho
também pode valer uma explicação um pouco mais detalhada.PHP, 126 bytes
Experimente online!
fonte
<?=($s=fgets(STDIN))?
C #,
8982 bytesUm 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.
fonte
var J="";...
1121
e1 2 1 2
são ambos OK} return J;};
using System.Text
ou mais ou menos - as importações não são gratuitas.Haskell, 85 bytes
fonte
map$...
Pitão, 17 bytes
Experimente online!
Use o ponto de código dos caracteres com algumas aritméticas.
fonte
C, 85 bytes.
Examina os 4 bits mais altos de cada byte para determinar a codificação e o número de bytes subsequentes a serem ignorados;
fonte
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.char*
, realmente) em C é marcado com um byte nulo. É impossível distinguir bytes nulos do final real da string.Fator,
57878280 bytesExplicado:
Testes unitários:
Todos eles passam agora. c:
fonte
Swift 2.2,
675250 bytesHorrivelmente 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
Character
em umString
e encontrar ocount
caractere ú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
count
vez deunderestimateCount()
.Revisões 2: salvou outro caractere 2 usando um loop for-in em vez de um para cada fechamento.
fonte
Ferrugem, 53 bytes
Rust possui utf-8 char primitives, iteradores e lambdas, portanto isso foi direto. Código do teste:
Saídas
fonte
jq, 26 caracteres
(Código de 23 caracteres + opção de linha de comando de 3 caracteres)
Espero competir. Embora tenha
utf8bytelength
sido adicionado 9 ++ meses antes desta pergunta, ainda não está incluído na versão lançada.Exemplo de execução:
fonte
C (gcc) , 53 bytes
Experimente online!
fonte
SmileBASIC, 69 bytes
Entrada é uma matriz de bytes.
O número de bytes em um caractere UTF-8 é igual ao número de
1
bits iniciais no primeiro byte (a menos que não haja1
s, nesse caso, o caractere é de 1 byte). Para encontrar o número de 1s iniciais, o programa encontra o primeiro0
na representação binária e adiciona 1 se esse for 0.fonte
F #,
595466 bytesTecnicamente, 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.
fonte
UTF-8 without BOM
, isso está errado e deve ser corrigido. 3) Parece que o F # precisa de instruções comolet 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|])}
.error FS0039: The namespace or module 'Encoding' is not defined
ao tentar executar isso. O que estou fazendo errado?System.Text
espaç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.import
,#include
,open
,load
,require
,using
,USING:
etc aqui na PPCG. A resposta C # do AstroDan é igualmente errônea, e eu os informei disso.05AB1E , 15 bytes
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:
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:Inspirado na resposta Python 3 de @TheBikingViking .
fonte
Zsh , 41 bytes
Experimente online!
Como o Zsh reconhece UTF-8, dividimos a sequência em caracteres, desativamos o multibyte e imprimimos o comprimento de cada caractere.
fonte