Bytes / Carácter


28

Tarea

Dada una cadena UTF-8 (por cualquier medio), responda (por cualquier medio) una lista equivalente donde cada elemento es el número de bytes utilizados para codificar el carácter de entrada correspondiente.

Ejemplos

!1

Ciao1 1 1 1

tʃaʊ1 2 1 2

Adám1 1 2 1

ĉaŭ2 1 2(caracteres individuales)

ĉaŭ1 2 1 1 2(utiliza superposiciones combinadas)

チャオ3 3 3

(entrada vacía) → (salida vacía)

!±≡𩸽1 2 3 4

(un byte nulo) → 1

Bytes nulos

Si la única forma de seguir leyendo la entrada más allá de los bytes nulos es conociendo el recuento total de bytes, puede obtener el recuento de bytes por cualquier medio (incluso la entrada del usuario).

Si su idioma no puede manejar bytes nulos, puede suponer que la entrada no contiene nulos.


1
Si la entrada está vacía, ¿podemos generar 0 u otro valor falsey?
Alex A.

2
¿Puedo imprimir el conteo de bytes sin separación? El valor más alto posible es 6, por lo que no es ambiguo.
Dennis

3
¿Tenemos que admitir bytes nulos? Esos pueden ser un verdadero dolor en algunos idiomas ...
Dennis

3
Deberías agregar eso a la publicación. No conozco la mayoría de los idiomas lo suficientemente bien como para saber si hay alguna diferencia, pero creo que invalida al menos dos de las respuestas.
Dennis

2
@ Adám sí lo hará. En C, por ejemplo, las cadenas C terminan con un byte NUL, por lo que deja de leer tan pronto como encuentra uno. Si conoce la longitud de la cadena, deja de leer después de tantos bytes, NUL y todo.
gato

Respuestas:


10

Pyth, 9 7 bytes

¡Gracias a @Maltysen por guardar 2 bytes!

mlc.Bd8

Banco de pruebas

Convierte cada carácter de la entrada en su representación binaria y luego lo divide en fragmentos de longitud 8. El número de esos fragmentos es la cantidad de bytes necesarios para codificar ese carácter.


1
puede guardar 2 bytes con división en lugar de dividir y luego eliminar .E pyth.herokuapp.com/…
Maltysen

@Maltysen Eso es inteligente, ¡gracias!
Denker

1
Respuesta de la misma longitud que se basa en un truco similar:mlhc8.B
FryAmTheEggman

@LeakyNun, entonces sería simple dar un caso de prueba que falla, ¿no?
Lause

Para guardar otro byte, en lugar de dividirse en trozos de 8, tome cada 8vo: ml%8.B(ahora el 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();}

¡Gracias a @FryAmTheEggman por jugar 3 bytes!

Pruébalo en Ideone .


11

APL, 15 caracteres

≢¨'UTF-8'∘⎕ucs¨

En inglés: convierta cada carácter a UTF-8 (significado: vector de representación de bytes) y obtenga su cuenta.


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

De hecho @ Adám ... Saludos.
lstefano

Un enfoque basado en una matriz interesante (pero más largo):+⌿0 7 11 16∘.≤2⍟⎕UCS
Adám

Versión 16.0:0 7 11 16⍸2⍟⎕UCS
Adám

7

GolfScript, 16 bytes

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

Pruébalo en línea!

Fondo

GolfScript no tiene idea de qué es Unicode; Todas las cadenas (entrada, salida, interna) están compuestas de bytes. Si bien eso puede ser bastante molesto, es perfecto para este desafío.

UTF-8 codifica caracteres ASCII y no ASCII de manera diferente:

  • Todos los puntos de código por debajo de 128 están codificados como 0xxxxxxx.

  • Todos los demás puntos de código están codificados como 11xxxxxx 10xxxxxx ... 10xxxxxx.

Esto significa que la codificación de cada carácter Unicode contiene un solo 0xxxxxxxbyte o un solo 11xxxxxxbyte y de 1 a 5 10xxxxxxbytes.

Al dividir todos los bytes de la entrada por 64 , nos convertimos 0xxxxxxxen 0 o 1 , 11xxxxxxen 3 y 10xxxxxxen 2 .

Si comparamos el cociente con 2 , presionamos 1 por 2 ; y 0 para 0 , 1 y 3 : cada carácter se convertirá en un 0 , seguido de 1 a 5 1 's.

Todo lo que queda es dividir la cadena resultante en ocurrencias de 0 , contar el número de 1 entre esos ceros y agregar uno a la cantidad.

Cómo 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($_)}

nótese bien

OK, esto debería funcionar, y lo hace en casi todos los casos de prueba, excepto 𩸽que de alguna manera se cuenta como 3,3en mi máquina. Ese personaje incluso se muestra como 7 bytes en mi computadora. Sospecho que esto se debe a algún tipo de error en la versión de Windows o .NET que estoy ejecutando localmente, ya que @Mego no tiene ese problema . ( Editar: @cat señala que esto se debe a BOM . ¡Gracias por resolver ese misterio, @cat! )

Sin embargo, eso todavía no explica todo el problema. Sin embargo, creo que sé de dónde provienen algunos de los problemas. Dentro de .NET, todas las cadenas están compuestas de unidades de código UTF-16 (que es el tipo System.Char). Con el tipo de letra muy flexible que usa PowerShell, hay una gran cantidad de conversión implícita y conversión entre tipos en segundo plano. Probablemente este es un factor que contribuye al comportamiento que estamos viendo, por ejemplo, [system.text.encoding]::utf8.getchars([System.Text.UTF8Encoding]::UTF8.GetBytes('𩸽'))devuelve dos caracteres no imprimibles, en lugar de un solo personaje.


Explicación

Código muy sencillo. Toma la entrada $args[0]y la convierte explícitamente como una matriz de caracteres para que podamos recorrer cada componente de la cadena |%{...}. En cada iteración, usamos la llamada .NET [System.Text.Encoding]::UTF8.GetByteCount()( System.está implícita) para obtener el recuento de bytes del carácter actual $_. Eso se coloca en la tubería para la salida posterior. Como se trata de una colección de [int]correos electrónicos devueltos, la conversión a una matriz es implícita.

Ejecuciones de prueba

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 agregar Esto explica adecuadamente el requisito de bytes nulos que se agregó al desafío después de que publiqué originalmente, siempre que extraiga los datos de un archivo de texto y los canalice de la siguiente manera:

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í, eso se debe a Byte-Order Mark, que es lo que obtienes en Windows con UTF-8. Indique a Notepad ++ que use UTF-8 without BOM(ya que siempre debe evitar la lista de materiales , especialmente para la compatibilidad con Unicies) y encontrará que el archivo tiene un tamaño de 4 bytes, porque la lista de materiales es 3 y 4 + 3 = 7
cat

@cat Ah, sí, eso tiene sentido. OK, eso explica la diferencia en el tamaño de los archivos. Sin embargo, eso todavía no explica el comportamiento diferente dentro del shell en sí. Por ejemplo, guardarlo como UTF-8 sin BOM y ejecutarlo get-content -Encoding UTF8 .\z.txt|%{.\bytes-per-character.ps1 $_}aún devuelve 3,3.
AdmBorkBork



6

JavaScript (ES6), 54 45 43 bytes

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

Editar: Guardado 2 bytes con ayuda de @ l4m2.


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

@ l4m2 Eso falla para los caracteres que no son BMP pero pude arreglarlo.
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 Perl 6 usa cadenas NFG, tengo que extraer los bytes directamente, lo que evita la función.
(NFG es como NFC, excepto que también crea puntos de código compuestos sintéticos)

La salida está separada por nuevas líneas.

Prueba:

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)

Explicación:

# 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

Esto funciona porque el primer byte en un punto de código de varios bytes tiene el número de bytes codificados dentro de él, y los otros bytes en el punto de código tienen el bit más alto establecido, pero no el siguiente más alto. Mientras que los puntos de código de un solo byte no tienen el bit más alto establecido.


No se puede hacer read:1y / o en su /while$lugar? ¿Y si eso funciona if$?
Erik the Outgolfer

@ EʀɪᴋᴛʜᴇGᴏʟғᴇʀ No, porque eso se analizaría como algo diferente. Aunque puedo eliminar el espacio antes while.
Brad Gilbert b2gills

¿Puedes explicar las contramedidas de NFG?
JDługosz

Si hago eco de un byte NUL al STDIN de este programa, se imprime \n1\n1\n, ¿es intencional? Básicamente, ¿esto maneja bytes NUL?
gato

@cat ¿Por qué no lo haría? Cuando hago esto: perl -e 'print "𩸽\0𩸽"' | perl6 -e '...'me sale 4␤1␤4como esperaba. (Sin embargo, la parte sobre nuls se agregó después de que
publiqué

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]

Esto es mucho más largo que la otra respuesta de Python, y la mayoría de las otras respuestas, pero utiliza un enfoque que involucra logaritmos que aún no he visto.

Una función anónima que toma la entrada, a través del argumento, como una cadena y devuelve una lista.

Pruébalo en Ideone

Cómo funciona

Este método se basa en la forma en que UTF-8 codifica el punto de código de un personaje. Si el punto de código es menor que 128, el carácter se codifica como en ASCII:

0xxxxxxx

donde xrepresenta los bits del punto de código. Sin embargo, para puntos de código mayores o iguales a 128, el primer byte se rellena con el mismo número de 1s que el número total de bytes, y comienzan los bytes subsiguientes 10. Los bits del punto de código se ingresan para obtener la secuencia multibyte más corta posible, y se convierten en los bits restantes 0.

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

Etcétera.

Ahora se puede notar que para cada número de bytes n, el límite superior para el número de bits de punto de código viene dado por (-n+7)+6(n-1) = 5n+1. Por lo tanto, el punto cde código de límite superior para cada uno nestá dado, en decimal, por c= 2^(5n+1). Reorganizar esto da n = (log2(c)-1)/5. Entonces, para cualquier punto de código, se puede encontrar el número de bytes evaluando la expresión anterior y luego tomando el techo.

Sin embargo, esto no funciona para los puntos de código en el rango 64 <= c <= 127, ya que la falta de un relleno 1debido a la codificación ASCII para caracteres de 1 byte significa que se predice el límite superior incorrecto y log2no está definido c = 0, lo que sucede si un byte nulo está presente en la entrada. Por lo tanto, si c <= 127, 1se devuelve un valor de n.

Esto es exactamente lo que está haciendo el código; para cada carácter ien la cadena x, el punto de código se encuentra usando la ordfunción, y el techo de la expresión se encuentra usando un entero en lugar de una división flotante 5y luego sumando 1. Dado que el tipo flotante de Python siempre representa enteros ya que x.0, incluso después de la división de enteros, el resultado se pasa a la intfunción para eliminar el cero final. Si ord(i) <= 127, un cortocircuito lógico significa que en 1su lugar se devuelve. El número de bytes para cada carácter se almacena como un elemento en una lista y se devuelve esta lista.


5

Java 10, 100 96 95 67 61 bytes

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

-4 bytes eliminando espacios porque esto está permitido en los comentarios
-1 byte cambiando UTF-8a utf8
-28 bytes pasando de Java 7 a 8 (en a->{...}lugar de void c(char[]i)throws Exception{...})
-3 bytes tomando la entrada como String-array en lugar de character-array, y
-3 bytes pasando de Java 8 a 10 (en varlugar de String)

Explicación:

Pruébalo en línea.

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?
gato

@cat Posteriormente se agregó el caso de prueba para bytes nulos. Pero sí, también funciona para bytes nulos y he agregado el caso de prueba.
Kevin Cruijssen

3

Julia, 34 bytes

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

Esta es una función anónima que acepta una cadena y devuelve una matriz entera. Para llamarlo, asígnelo a una variable.

El enfoque es bastante sencillo: si la entrada está vacía, la salida está vacía. De lo contrario, asignamos la sizeoffunción, que cuenta el número de bytes en una cadena, a cada subcadena de un carácter.

Pruébalo en línea! (incluye todos los casos de prueba)


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

Impar; no split("","")no volver []? (JavaScript "".split("")sí.)
Neil

@Neil split("","")parece dar ""(a diferencia de Python que da una excepción) pero no sé nada sobre la compatibilidad de []y ""en julia.
gato

@Neil No, split("", "") == [""]es decir, una matriz de un elemento que contiene una cadena vacía, pero el problema es que sizeof("") == 0el OP dijo que no está permitido.
Alex A.

@Dennis Eso fallará para cadenas no indexables. (Sin embargo, no puedo pensar en un ejemplo de improviso.)
Alex A.

3

PHP, 92 57 bytes

Pensándolo bien, puedes hacer esto con mucho menos engaño:

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

Pruébelo en línea, tenga en cuenta que esto es un poco más largo ya que utiliza stdin en lugar de un argumento de programa.
Esta versión requiere que ignore los avisos enviados a stderr, pero está bien .

versión anterior:
utiliza un enfoque bastante diferente a la otra respuesta php. Se basa en la falta de soporte nativo para cadenas de varios bytes en php.

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

¡Buena respuesta! Creo que puede soltar la etiqueta de apertura por completo, o cambiarla a<?=
cat

Sin la etiqueta, es un fragmento de código en lugar de un programa, e incluso si eso está permitido, me hace sentir vagamente sucio. Con la etiqueta alternativa, obtienes un error de análisis (o al menos lo hice en php 5.5, que es a lo que estoy acostumbrado).
user55641

Bien :) No sé PHP (ni quiero toser ) pero te señalaré aquí: codegolf.stackexchange.com/questions/2913
cat

3

Emacs Lisp, 55 49 bytes

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

Primero disecciona la cadena en una lista de caracteres con (mapcar 'string s). La stringfunción en Emacs Lisp toma una lista de caracteres y construye una cadena a partir de ellos. Debido a la forma en que Emacs divide cadenas mapcar(es decir, en una lista de enteros, no caracteres o cadenas), esta conversión explícita es necesaria. Luego asigna la string-bytesfunción a esa lista de cadenas.

Ejemplo:

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

Casos de prueba:

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

Vieja respuesta:

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

Sin golf:

 (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 prueba:

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


¿Qué pasa con el nilsi aplana el resultado?
Adám

1
@ Adám niles una lista vacía (y la única forma de decir "falso" en Emacs). Si bien no hay un aplanamiento estándar en Emacs (puede usar guiones -flatten), cualquier implementación posible lo eliminaría.
Lord Yuuma

3

JavaScript (nodo), 27 bytes

s=>s.map(Buffer.byteLength)

Esto toma la entrada como una matriz de caracteres individuales y devuelve una matriz de recuentos de bytes.

Bufferes un método para representar datos binarios sin procesar. Buffer.byteLength (cadena) da el número de bytes en la cadena. UTF-8 es la codificación predeterminada. Tenga en cuenta que solo Node.js tiene buffers, no el navegador JS. El equivalente aproximado del navegador se llama Blob , que viene en 31 bytes:

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

Prueba

Guarde este archivo y ejecútelo a través del nodo, o pruébelo en línea .

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 debería ser el 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

Golfed

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

Algoritmo

cadena de entrada hexdump, doble 2 caracteres por línea, corte solo el primer carácter

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

2
c
b
e
8
a
f
a
b
b

(4 bits de orden superior de cada byte de entrada como un carácter hexadecimal, uno por línea)

Eliminar "bytes de continuación" 0x80..0xBF

tr -d '89ab'

2
c

e


f

(lo que queda son 4 bits del primer byte de cada carácter unicode)

mapear los primeros bits en la longitud del carácter, contraer la salida e imprimir

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

1 2 3 4

Prueba

 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 Buen enfoque. En realidad, lee el resultado directamente de la entrada.
Adám

La -topción a trno me era familiar, y aparentemente es una extensión de GNU. La canalización a la sustitución de comandos después echotambién podría valer una explicación un poco más detallada.
tripleee


2

DO#, 89 82 bytes

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

Una simple lambda de C # que itera a través de la cadena y devuelve la lista separada por espacios.

Editar: guardado 6 bytes gracias a algunos comentarios muy agradables.


bastante seguro de que puedes hacerlovar J="";...
gato

Además, el OP indica en un comentario que no es necesario separar el espacio de la salida, 1121y 1 2 1 2ambos están bien
cat

1
@cat Gracias, me ahorró 6 bytes
AstroDan

Además, tiene un espacio adicional en} return J;};
gato

Parece que lo necesita using System.Texto por ahí: las importaciones no son gratuitas.
gato

2

Haskell, 85 bytes

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

Un poco tarde, pero esto sería más corto comomap$...
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 los 4 bits altos de cada byte para determinar la codificación y el número de bytes subsiguientes que se omitirán;


¿Funciona esto en bytes nulos?
gato

Sí, las while *c salidas en una cadena vacía, y el 'c + = d' omite nulos en el medio de un punto de código de múltiples bytes.
AShelly

1
Eso es incorrecto El final de una cadena ( char*, realmente) en C está marcado con un byte nulo. Es imposible distinguir los bytes nulos del final real de la cadena.
Dennis

@Dennis Precisamente porque no hay diferencia :)
gato

1
El OP declaró en un comentario (y ahora está en la publicación) que puede solicitar la longitud de la cadena en bytes como argumento, así que hágalo y esto será válido nuevamente
cat

1

Factor, 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

Pruebas unitarias:

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 pasan, ahora. do:


1

Swift 2.2, 67 52 50 bytes

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

Horriblemente feo. No hay forma de obtener la longitud UTF-8 de un personaje en Swift, así que necesito iterar a través de la cadena por carácter, convertir el Charactera a Stringy encontrar el countde ese carácter únicoString (hey, al menos hay un incorporado) método para hacer eso). Buscando optimizaciones, posiblemente usando un escáner.

Revisión 1: se guardaron 15 bytes utilizando en countlugar de underestimateCount().

Revisiones 2: guardó otros 2 caracteres mediante el uso de un bucle for-in en lugar de un para cada cierre.


1

Óxido, 53 bytes

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

Rust tiene primitivas de caracteres utf-8, iteradores y lambdas, por lo que esto fue sencillo. Código de prueba:

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

Salidas

1211133112111114444 

1

jq, 26 caracteres

(Código de 23 caracteres + opción de línea de comando de 3 caracteres)

(./"")[]|utf8bytelength

Con suerte compitiendo. Aunque utf8bytelengthera agregó 9 ++ meses antes de esta pregunta, todavía no se incluye en la versión lanzada.

Ejecución de muestra:

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

La entrada es una matriz de bytes.

El número de bytes en un carácter UTF-8 es igual al número de 1bits iniciales en el primer byte (a menos que no haya 1s, en cuyo caso el carácter es 1 byte). Para encontrar el número de 1 principales, el programa encuentra el primero0 en la representación binaria, luego agrega 1 si fue 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|])}

Técnicamente, s es una secuencia de caracteres, pero resulta que hay una conversión implícita que permite pasar una cadena.

Al probar esto en la consola con !±≡𩸽 , divide el kanji en dos caracteres, cada uno de 3 bytes de longitud. Todos los demás casos de prueba funcionan bien.

Editar: Resulta que las importaciones de espacios de nombres comunes no están implícitas. Hasta otros 12 caracteres.


1) La respuesta de PowerShell de Timmy D tiene el mismo problema de 6 bytes por kanji. Lo atribuiría a que Windows es tonto e inútil en Unicode. 2) Si obtienes 6 bytes para el kanji cuando lees de un archivo codificado, UTF-8 without BOMentonces esto es incorrecto y debería repararse . 3) Parece que F # necesita declaraciones como let f(x)= ...para terminar ;;, como SML. 4) Puede dejar de asignar un nombre a esta función anónima, es decir (s)=seq{for c in s->Encoding.UTF8.GetByteCount([|c|])}.
gato

Además, me sale error FS0039: The namespace or module 'Encoding' is not definedcuando intento ejecutar esto. ¿Qué estoy haciendo mal?
gato

Además, bienvenido a Programming Puzzles y Code Golf, ¡esta es una buena primera respuesta! : D
gato

@cat Necesita abrir el System.Textespacio de nombres. Supongo que se abre el espacio de nombres y se incluye el código de entrada, proveniente de la respuesta de C # de AstroDan.
interfaz sellada

Es necesario contar los bytes de cualquier import, #include, open, load, require, using, USING:etc aquí en PPCG. La respuesta de C # de AstroDan es igualmente errónea, y se lo notifiqué.
gato

1

05AB1E , 15 bytes

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

Pruébalo en línea.
El encabezadoεse utiliza para cada uno de los casos de prueba;
Pieï]J]»depáginapara imprimir bonitas las listas de caracteres de salida (ï: decimales y caracteres a enteros;:]cierre if-else y for-eachJ;: unir dígitos juntos};: cerrar encabezado foreach;» unirse por nuevas líneas).

Explicación:

Ç                   # 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 05AB1E no tiene ninguna función incorporada para convertir caracteres a la cantidad de bytes utilizados, utilizo Çpara convertir los caracteres a sus valores unicode, y para cada uno, haga lo siguiente en pseudocódigo:

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

Inspirado por la respuesta de Python 3 de @TheBikingViking .


0

Zsh , 41 bytes

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

Pruébalo en línea!

Zsh es compatible con UTF-8, por lo que dividimos la cadena en los caracteres, luego deshabilitamos multibyte e imprimimos la longitud de cada carácter.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.