Longitud de una secuencia de bytes UTF-8

15

Determine la longitud de una secuencia de bytes UTF-8 dado su primer byte. La siguiente tabla muestra qué rangos se asignan a cada longitud posible:

  Range    Length
---------  ------
0x00-0x7F    1
0xC2-0xDF    2
0xE0-0xEF    3
0xF0-0xF4    4

Notas sobre los espacios en la tabla: 0x80-0xBF son bytes de continuación, 0xC0-0xC1 comenzaría una secuencia demasiado larga e inválida, 0xF5-0xFF resultaría en un punto de código más allá del máximo Unicode.

Escriba un programa o función que tome el primer byte de una secuencia de bytes UTF-8 como entrada y salida o devuelva la longitud de la secuencia. I / O es flexible. Por ejemplo, la entrada puede ser un número, un carácter de 8 bits o una cadena de un carácter. Puede suponer que el primer byte es parte de una secuencia válida y cae en uno de los rangos anteriores.

Este es el código de golf. La respuesta más corta en bytes gana.

Casos de prueba

0x00 => 1
0x41 => 1
0x7F => 1
0xC2 => 2
0xDF => 2
0xE0 => 3
0xEF => 3
0xF0 => 4
0xF4 => 4
nwellnhof
fuente
¿Es aceptable una entrada de una lista de los 8 bits?
Jonathan Allan
@JonathanAllan No, eso llevaría las E / S flexibles demasiado lejos.
nwellnhof

Respuestas:

5

Adelante, 6 bytes

x-size

ver https://forth-standard.org/standard/xchar/X-SIZE

La entrada y salida sigue un modelo estándar de Forth:

Entrada

Dirección de memoria + longitud (es decir, 1) de una "cadena" UTF-8 de un solo byte.

Salida

Longitud de secuencia UTF-8 en bytes.

Código de muestra

Almacene 0xF0 en una celda de memoria e invoque x-size:

variable v
0xF0 v !
v 1 x-size

Comprueba el resultado:

.s <1> 4  ok
zepelín
fuente
Suponiendo que esto funcione en tio.run/#forth-gforth , ¿podría mostrar un ejemplo? No entiendo cómo podría tener una cadena UTF-8 de un solo byte si el byte es 0xF0.
Dennis
> ¿podrías mostrar un ejemplo? No entiendo cómo podría tener una cadena UTF-8 de un solo byte si el byte es 0xF0. He agregado un código de muestra que demuestra cómo hacerlo. Desafortunadamente, la versión TIO de gforth no parece admitir las palabras Unicode (de acuerdo con "ver tamaño x", solo está codificado para devolver 1 allí).
zepelín
Veo. Sin embargo, eso no es lo que llamaría una cadena UTF-8, ya que F0 solo es una secuencia de bytes no válida, en lo que respecta a UTF-8.
Dennis
> como F0 solo es una secuencia de bytes inválida Verdadero (es por eso que he puesto la palabra "cadena" entre comillas), pero esta tarea se trata específicamente de reconocer la secuencia por su primer byte, y a Forth realmente no le importa que sea inválida , lo que hace posible esta solución, a su vez.
zeppelin
6

Z80Golf , 19 14 bytes

00000000: 2f6f 3e10 37ed 6a3d 30fb ee07 c03c       /o>.7.j=0....<

Pruébalo en línea!

-5 bytes gracias a @Bubbler

Ejemplo con entrada 0x41-¡Pruébelo en línea! Montaje

Ejemplo con entrada 0xC2: ¡Pruébelo en línea!

Ejemplo con entrada 0xE0-¡Pruébelo en línea!

Ejemplo con entrada 0xF4: ¡Pruébelo en línea!

Montaje:

;input: register a
;output: register a
byte_count:			;calculate 7^(log2(255^a))||1
	cpl			;xor 255
	ld l,a
	log2:
		ld	a,16
		scf
	log2loop:
		adc	hl,hl
		dec	a
		jr	nc,log2loop
	xor 7
	ret nz
	inc a

Pruébalo en línea!

Logern
fuente
Use Bash TIO para trabajar con ensamblaje, con ejemplos más fáciles de ver. El enlace también tiene una versión de 15 bytes de su solución. Aquí están las mejoras: xor 0xff -> cpl, no hay necesidad de or a, jr nz, return -> ret nz, ld a,1 -> inc a.
Bubbler
5

C (gcc) , 39 bytes

t(char x){x=(__builtin_clz(~x)-24)%7u;}

Pruébalo en línea!

usuario202729
fuente
¿Por qué chary no int?
R .. GitHub DEJA DE AYUDAR AL HIELO
@R .. Porque obtienen señal extendida. Por ejemplo ~(char)0xF0 == ~(int)0xFFFFFFF0(se supone char = signed char, sizeof(int) == 4)
user202729
Ah, suponiendo que Char esté firmado.
R .. GitHub DEJA DE AYUDAR AL HIELO
4

Jalea ,  8  7 bytes

+⁹BIITḢ

Un enlace monádico que acepta el byte como un entero.

Pruébalo en línea! O ver todas las entradas evaluadas .

Si una entrada de una lista de los 8 bits fuera aceptable, entonces el método es de solo 6 bytes: 1;IITḢsin embargo, se considera que habla de E / S flexible demasiado lejos.

¿Cómo?

+⁹BIITḢ - Link: integer       e.g.: 127 (7f)            223 (df)            239 (ef)            244 (f4)
 ⁹      - literal 256
+       - add                       383                 479                 495                 500
  B     - to a list of bits         [1,0,1,1,1,1,1,1,1] [1,1,1,0,1,1,1,1,1] [1,1,1,1,0,1,1,1,1] [1,1,1,1,1,0,1,0,0]
   I    - increments                [-1,1,0,0,0,0,0,0]  [0,0,-1,1,0,0,0,0]  [0,0,0,-1,1,0,0,0]  [0,0,0,0,-1,1,-1,0]
    I   - increments                [2,-1,0,0,0,0,0]    [0,-1,2,-1,0,0,0]   [0,0,-1,2,-1,0,0]   [0,0,0,-1,2,-2,1]
     T  - truthy indices            [1,2]               [2,3,4]             [3,4,5]             [4,5,6,7]
      Ḣ - head                      1                   2                   3                   4
Jonathan Allan
fuente
3

Jalea , 8 7 bytes

»Ø⁷Ba\S

Pruébalo en línea!

Cómo funciona

»Ø⁷Ba\S  Main link. Argument: n (integer)

 Ø⁷      Yield 128.
»        Take the maximum of n and 128.
   B     Yield the array of binary digits.
    a\   Cumulatively reduce by AND, replacing 1's after the first 0 with 0's.
      S  Take the sum.
Dennis
fuente
1

Carbón de leña , 12 bytes

I⌕⍘⌈⟦N¹²⁸⟧²0

Pruébalo en línea! El enlace es a la versión detallada del código. Explicación:

     N          Input number
      ¹²⁸       Literal 128
   ⌈⟦    ⟧      Take the maximum
  ⍘       ²     Convert to base 2 as a string
 ⌕         0    Find the position of the first `0`
I               Cast to string
                Implicitly print
Neil
fuente
1

Perl 6 , 18 bytes

{7-msb(255-$_)||1}

Pruébalo en línea!

Puerto de la respuesta de JavaScript de user202729. Alternativas con WhateverCode:

(255-*).msb*6%34%7
-(255-*).msb%6%5+1
nwellnhof
fuente
1

Asamblea x86, 11 bytes

00000000 <f>:
   0:   f6 d1                   not    %cl
   2:   0f bd c1                bsr    %ecx,%eax
   5:   34 07                   xor    $0x7,%al
   7:   75 01                   jne    a <l1>
   9:   40                      inc    %eax
0000000a <l1>:
   a:   c3                      ret

Pruébalo en línea!

Puerto de la respuesta de JavaScript de user202729. Utiliza convenciones de llamada rápida.

nwellnhof
fuente
1

05AB1E , 8 7 bytes

žy‚àb0k

Puerto de la respuesta de carbón de @Neil .
-1 byte gracias a @Grimy .

Entrada como entero.

Pruébelo en línea o verifique todos los casos de prueba .

Explicación:

žy       # Push 128
        # Pair it with the (implicit) input-integer
   à     # Take the maximum of this pair (128 and input)
    b    # Convert it to a binary-string
     0k  # Get the 0-based first index of a "0" in this binary-string
         # (and output it implicitly as result)
Kevin Cruijssen
fuente
1
s)a para 7. La portabilidad de la otra respuesta de Jelly da otro 8:₁+b¥η€ËO
Grimmy el
@Grimy No tengo idea de por qué no tuve en primer lugar ...: S Pero gracias por -1.
Kevin Cruijssen
0

C, 31 bytes

f(x){return(x-160>>20-x/16)+2;}

Pruébalo en línea!

27 bytes con gcc (-O0)

f(x){x=(x-160>>20-x/16)+2;}

Alternativas, 31 y 33 bytes.

f(x){return(10>>15-x/16)+7>>2;}
f(x){return x/128-(-3>>15-x/16);}

¡Encontré estas expresiones al jugar con el Aha! superoptimizador hace unos años .

nwellnhof
fuente