Calculadora de caracteres de control de tarjeta de identificación española

20

Este es un algoritmo muy muy simple, que estoy seguro se puede resolver en muchos idiomas diferentes. En España, las tarjetas de identificación (conocidas como DNI ) constan de 8 números y un carácter de control. El carácter de control se calcula con el siguiente algoritmo: divida el número entre 23, tome el resto de la operación y reemplácelo con un carácter de acuerdo con esta tabla:

0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22  
T  R  W  A  G  M  Y  F  P  D  X  B  N  J  Z  S  Q  V  H  L  C  K  E

Si el DNI pertenece a una persona extranjera que vive en España, el primer dígito se cambia a X, Yo Zy se llama NIE . En este caso, se realizan las siguientes sustituciones antes de calcular el carácter de control:

X Y Z
0 1 2

Hay muchas calculadoras en línea que lo ayudan a obtener el carácter de control, pero, ¿qué tan corto puede escribir ese código? Escriba un algoritmo (programa o función) que reciba un stringcon el número DNI (que siempre constará de 8 caracteres alfanuméricos) y devuelva solo el carácter de control único calculado y nada más (se acepta una nueva línea final).

Notas:

  • El DNI siempre se escribe en mayúsculas, pero en su algoritmo puede elegir que la entrada y la salida sean mayúsculas o minúsculas, solo sea coherente.
  • En la vida real, algunos NIE emitidos antes de 2008 tienen 8 dígitos después del X, Yo Z, pero para los propósitos de este juego, puedes considerar que tienen 7 dígitos como lo tienen hoy en día.
  • Puede considerar que la cadena de entrada siempre tendrá 8 caracteres, pero si no están en el formato "8 dígitos" ni en el formato "[XYZ] más 7 dígitos", debe devolver un error (de su elección) o simplemente lanzar una excepción.

Casos de prueba:

00000010 -> X (HRM Juan Carlos I's DNI number)
01234567 -> L
98765432 -> M
69696969 -> T
42424242 -> Y
Z5555555 -> W (Z=2)
Y0000369 -> S (Y=1)
A1234567 -> <Error code or exception>
1231XX12 -> <Error code or exception>

Este es el , ¡así que puede ganar el código más corto para cada idioma!

Charlie
fuente
Caja de arena .
Charlie
2
¿Es realmente importante que el código tenga un comportamiento específico en una entrada no válida? Por lo general, los desafíos aquí no requieren preocuparse por el manejo de errores.
Greg Martin
3
@GregMartin precisamente, solo quería que el código mostrara un comportamiento específico en las entradas de error, ya que generalmente no es necesario.
Charlie
En "divide el número entre 23, toma el resto de la operación", el término correcto es el resto ; el descanso es demasiado coloquial.
Locoluis
2
@Locoluis en español decimos resto , haciendo "descanso" un falso amigo, entonces. Al menos no usé un término incorrecto. :-) ¡Gracias!
Charlie

Respuestas:

11

Python 3 , 83 bytes

lambda n:'TRWAGMYFPDXBNJZSQVHLCKE'[int([n,str(ord(n[0])%4)+n[1:]][n[0]in'XYZ'])%23]

Pruébalo en línea!

-5 gracias a AlixEinsenhardt (de 99 a 94). -1 gracias a JonathanAllan .

Sr. Xcoder
fuente
1
Se puede reemplazar str('XYZ'.index(n[0]))por str(ord(n[0])-88)y guardar 5 bytes
Alix Eisenhardt
1
@AlixEisenhardt La sugerencia anterior me inspiró a cambiar la técnica a una lambda, que finalmente ahorró 10 bytes.
Sr. Xcoder
Guarde un byte reemplazándolo -88con %4.
Jonathan Allan
8

Haskell , 107 93 92 bytes

c(x:y)="TRWAGMYFPDXBNJZSQVHLCKE"!!mod(read(("X0Y1Z2"!x):y))23
(a:b:c)!x|x==a=b|2>1=c!x
_!x=x

Pruébalo en línea!

bartavelle
fuente
¿Cuál es el comportamiento de las entradas no válidas?
Charlie
Bloquearán el programa, agregué uno en el ejemplo. (en la práctica arroja una excepción que nadie atrapa)
bartavelle
1
Actualicé el envío con la captura de excepciones, para que todas las pruebas pudieran ejecutarse.
bartavelle
5

Pyth, 35 34 bytes

El código contiene algunos caracteres no imprimibles, por lo que aquí hay un xxdhexdump reversible .

00000000: 402e 5043 22fc eeff 1ffc adc7 e614 9451  @.PC"..........Q
00000010: 2247 2573 7358 637a 5d31 3e33 4755 3320  "G%ssXcz]1>3GU3
00000020: 3233                                     23

Utiliza caracteres en minúscula .

Pruébalo en línea. Banco de pruebas.

Versión imprimible

@.P305777935990456506899534929G%ssXcz]1>3GU3 23

Explicación

  • cz]1divide la entrada en la posición 1, por ejemplo, "y0000369"a ["y", "0000369"].
  • >3Gobtiene los 3 últimos caracteres del alfabeto, "xyz".
  • U3obtiene el rango [0, 3 [ , [0, 1, 2].
  • Xasigna xyza [0, 1, 2]en la matriz dividida, por ejemplo, ["y", "0000369"]a [1, "0000369"]. Esto reemplaza el primer carácter si es uno de ellos xyz, sin tocar la cola de 7 caracteres, ya que cualquier cadena de 7 caracteres no puede ser igual a un solo carácter.
  • sune la matriz con la cadena vacía, por ejemplo, [1, "0000369"]a "10000369".
  • sconvierte esta cadena a entero, por ejemplo, "10000369"a 10000369. Esto arroja un error si quedan caracteres adicionales que no sean dígitos en la cadena.
  • %... 23obtiene el valor del módulo 23, por ejemplo, 10000369a 15.
  • C""Convierte la cadena binaria de base 256 a entero (aproximadamente 3.06 × 10 26 ).
  • .P... Gobtiene la permutación del alfabeto con ese índice.
  • @ obtiene el carácter correcto de la permutación.
PurkkaKoodari
fuente
4

MATL , 62 59 bytes

'RWAGMYFPDXBNJZSQVHLCKET'j'[\dXYZ]\d{7}'XXg'XYZ'I:47+XEU1))

El error para una entrada no válida es A(I): index out of bounds(el compilador se ejecuta en Octave) o Index exceeds matrix dimensions(el compilador se ejecuta en Matlab).

Pruébalo en línea!

Explicación

'RWAGMYFPDXBNJZSQVHLCKET' % Push this string (output letters circularly shifted by 1)
j                         % Unevaluated input
'[\dXYZ]\d{7}'            % Push this string (regexp pattern)
XX                        % Regexp. Returns cell arary with matching string, or empty
g                         % Convert to standard array. Will be empty if non-valid input
'XYZ'                     % Push this string
I:47+                     % Push [47 48 49] (ASCII codes of '012')
XE                        % Transliterate
U                         % Convert to number
1)                        % Get first entry. Gives an error if empty
)                         % Index (modular, 1-based) into initial string
                          % Implicitly display
Luis Mendo
fuente
4

ES6, 83 82 81 bytes

i=>'TRWAGMYFPDXBNJZSQVHLCKE'[(/^[XYZ]/.test(i)?i.charCodeAt()%4+i.slice(1):i)%23]

¡En acción!

Solo en mayúsculas, el código de error para números no válidos es undefined.

Un byte guardado gracias a Jonathan Allan.
Otro byte guardado gracias a Shaggy.

2ndAttmt
fuente
Tal vez guardar un byte usando en %4lugar de -88.
Jonathan Allan
Usted debe ser capaz de bajar la 0de charCodeAt()también.
Shaggy
3

Java 8, 154 145 104 bytes

s->{s[0]-=s[0]<88|s[0]>90?0:40;return"TRWAGMYFPDXBNJZSQVHLCKE".charA‌​t(new Integer(new String(s))%23);}

-9 bytes gracias a @ OliverGrégoire .
-41 bytes gracias a @ OliverGrégoire nuevamente, tomando la entrada como una matriz de caracteres ( char[]).

Si la entrada no es válida, fallará con un java.lang.NumberFormatExceptiono java.lang.StringIndexOutOfBoundsException.

Explicación:

Pruébalo aquí (Los casos de prueba no válidos están rodeados por try-catch para que no se detenga en el primer error).

s->{                      // Method with char[] parameter and char return-type
  s[0]-=s[0]<88|s[0]>90?  // If the first character is not XYZ:
    0                     //  Leave the first character as is
   :                      // Else:
    40;                   //  Subtract 40 to convert it to 012
  return"TRWAGMYFPDXBNJZSQVHLCKE".charAt(
                          //    Get the char from the String
    new Integer(          //    by converting the following String to an integer:
      new String(s)       //     by converting the char-array to a String
    )%23);                //    And take modulo-23 of that integer
}                         // End of method
Kevin Cruijssen
fuente
1
No necesitas el |en la expresión regular. Además int t=s.charAt(0)-88y t<0?t+40:tahorrarte un byte.
Olivier Grégoire
1
Finalmente, puede devolver un código de error. Simplemente decida si es 'a'o '0'no una letra mayúscula, y devuélvala en lugar de t/0y eche todo el lote a char. Supongo que ahorraría 7 bytes de esta manera. Golfizado de esta manera , obtienes 145 bytes.
Olivier Grégoire
1
@ OlivierGrégoire Gracias! Tengo la sensación de que todavía es posible utilizar una forma diferente de validación en lugar de .matchescon esta expresión regular, por cierto. Pero tal vez estoy equivocado.
Kevin Cruijssen
1
No, tienes toda la razón! Es factible así: s->{s[0]-=s[0]<88?0:40;return"TRWAGMYFPDXBNJZSQVHLCKE".charAt(new Integer(new String(s))%23);}por solo 94 bytes (con sser a char[]): p
Olivier Grégoire
1
O si desea completar la validación: s[0]<88&s[0]>90para 8 bytes más.
Olivier Grégoire
2

PHP , 88 bytes

imprime 1 por un error

$a[0]=strtr(($a=$argn)[0],ZYX,210);echo!ctype_digit($a)?:TRWAGMYFPDXBNJZSQVHLCKE[$a%23];

Pruébalo en línea!

Jörg Hülsermann
fuente
2

Jalea , 42 bytes

“X0Y1Z2”⁸y@1¦RṪ€V%23ị“Ñ×ⱮEɼiʋ}'uƒẹsø’ṃØA$¤

Pruébalo en línea!

Demasiado tiempo, Jelly! ¡Dennis está decepcionado de ti! [cita requerida]

Erik el Outgolfer
fuente
1

q / kdb +, 68 bytes

Solución:

{"TRWAGMYFPDXBNJZSQVHLCKE"mod["J"$$[3>a:"XYZ"?x 0;($)a;x 0],1_x;23]}

Ejemplos:

q){"TRWAGMYFPDXBNJZSQVHLCKE"mod["J"$$[3>a:"XYZ"?x 0;($)a;x 0],1_x;23]}"00000010"
"X"
q){"TRWAGMYFPDXBNJZSQVHLCKE"mod["J"$$[3>a:"XYZ"?x 0;($)a;x 0],1_x;23]}"01234567"
"L"
q){"TRWAGMYFPDXBNJZSQVHLCKE"mod["J"$$[3>a:"XYZ"?x 0;($)a;x 0],1_x;23]}"98765432"
"M"
q){"TRWAGMYFPDXBNJZSQVHLCKE"mod["J"$$[3>a:"XYZ"?x 0;($)a;x 0],1_x;23]}"69696969"
"T"
q){"TRWAGMYFPDXBNJZSQVHLCKE"mod["J"$$[3>a:"XYZ"?x 0;($)a;x 0],1_x;23]}"42424242"
"Y"
q){"TRWAGMYFPDXBNJZSQVHLCKE"mod["J"$$[3>a:"XYZ"?x 0;($)a;x 0],1_x;23]}"Z5555555"
"W"
q){"TRWAGMYFPDXBNJZSQVHLCKE"mod["J"$$[3>a:"XYZ"?x 0;($)a;x 0],1_x;23]}"Y0000369"
"S"
q){"TRWAGMYFPDXBNJZSQVHLCKE"mod["J"$$[3>a:"XYZ"?x 0;($)a;x 0],1_x;23]}"A1234567"
" "
q){"TRWAGMYFPDXBNJZSQVHLCKE"mod["J"$$[3>a:"XYZ"?x 0;($)a;x 0],1_x;23]}"1231XX12"
" "

Explicación:

Si el primer carácter,, x 0está en la cadena, "XYZ"entonces aserá 0, 1o 2. Si el primer carácter no está en la cadena, entonces alo estará 3. Si aes menor que 3, cambiamos el primer carácter por la cadena de un ( 0, 1o 2), de lo contrario, cambiamos por el primer carácter (por lo tanto, no hacemos nada). Esta cadena se convierte en un largo ( "J"$), que luego se mod'd con 23 para dar el resto. Este resto se utiliza para indexar en la tabla de búsqueda.

{ "TRWAGMYFPDXBNJZSQVHLCKE" mod["J"$$[3>a:"XYZ"?x 0;string a;x 0],1_x;23] } / ungolfed solution
{                                                                         } / lambda function
                            mod[                                     ;23]   / performds mod 23 of the stuff in the gap
                                                                  1_x       / 1 drop input, drops the first character
                                                                 ,          / concatenation
                                    $[             ;        ;   ]           / if COND then TRUE else FALSE - $[COND;TRUE;FALSE]
                                        a:"XYZ"?x 0                         / "XYZ" find x[0], save result in a
                                      3>                                    / is this result smaller than 3
                                                    string a                / if so, then string a, e.g. 0 -> "0"
                                                             x 0            / if not, just return first character x[0]
                                "J"$                                        / cast to long
  "TRWAGMYFPDXBNJZSQVHLCKE"                                                 / the lookup table

Notas:

" "se devuelve en los escenarios de error, esto se debe a que la conversión devuelve un valor nulo, y la indexación en una cadena en el índice nulo es un carácter vacío. Podría agregar 4 bytes al principio ( "!"^) para que sea más obvio que se ha producido un error:

q){"!"^"TRWAGMYFPDXBNJZSQVHLCKE"("J"$$[3>a:"XYZ"?x 0;($)a;x 0],1_x)mod 23}"1231XX12"
"!"
callejero
fuente
1

JavaScript (ES6), 121 bytes

f=i=>{c=+i[0];a=3;while(a--){i[0]=="XYZ"[a]&&(c=a)}b=7;while(b--){c= +i[7-b]+c*10}return "TRWAGMYFPDXBNJZSQVHLCKE"[c%23]}

console.log([f("00000010"),f("01234567"),f("98765432"),f("69696969"),f("42424242"),f("Z5555555"),f("Y0000369"),f("A1234567"),f("1231XX12")])

Евгений Новиков
fuente
1

Óxido, 206 bytes

No creo que el óxido sea adecuado para golf de código -_-

let b=|s:&str|{s.chars().enumerate().map(|(i,c)|match i{0=>match c{'X'=>'0','Y'=>'1','Z'=>'2',_=>c},_=>c}).collect::<String>().parse::<usize>().ok().and_then(|x|"TRWAGMYFPDXBNJZSQVHLCKE".chars().nth(x%23))};
dgel
fuente
1

05AB1E , 41 40 39 bytes

ć…xyz2ÝJ‡ìDd_i.ǝ}23%.•Xk¦fΣT(:ˆ.Îðv5•sè

Toma la entrada en minúsculas (para guardar 1 byte yay )

Pruébalo en línea!

Imprime la entrada a STDERR si está mal formada

Explicación

ć…xyz2ÝJ‡ìDd_i.ǝ}23%.•Xk¦fΣT(:ˆ.Îðv5•sè
ć                                       # Get head of input and put the rest of the input under it on the stack
 …xyz                                   # Push xyz
     2ÝJ                                # Push 012
        ‡                               # Transliterate
         ì                              # Prepend to the rest of the input
          Dd_                           # Does the result contain something other than numbers?
             i.ǝ}                       # If so print input to STDERR
                 23%                    # Modulo 23
                    .•Xk¦fΣT(:ˆ.Îðv5•   # Pushes the character list
                                     sè # Get the char at the index of the modulo
Datboi
fuente
0

Dyalog APL, 95 bytes

{'TRWAGMYFPDXBNJZSQVHLCKE'[1+23|(10⊥¯1+'0123456789'⍳{(⍕{('XYZ'⍳⍵)<4:('XYZ'⍳⍵)-1⋄⍵} ⊃⍵),1↓⍵}⍵)]}

Este es un operador monádico que acepta una cadena de caracteres como su operando y devuelve su resultado.

FIXME no verifica su entrada. No está bien golfizado.

Uso:

    OP ← {'TRWAGMYFPDXBNJZSQVHLCKE'[1+23|(10⊥¯1+'0123456789'⍳{(⍕{('XYZ'⍳⍵)<4:('XYZ'⍳⍵)-1⋄⍵} ⊃⍵),1↓⍵}⍵)]}

      OP '01234567'
L

      OP '00000010'
X
Locoluis
fuente