Calcolatore di caratteri per il controllo della carta d'identità spagnola


20

Questo è un algoritmo molto semplice, che sono sicuro che può essere risolto in molte lingue diverse. In Spagna le carte d'identità (note come DNI ) sono composte da 8 numeri e un carattere di controllo. Il carattere di controllo viene calcolato con il seguente algoritmo: dividere il numero per 23, prendere il resto dell'operazione e sostituirlo con un carattere secondo questa tabella:

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

Se il DNI appartiene ad una persona straniera che vive in Spagna, la prima cifra viene modificato in X, Yo Ze si chiama un NIE . In questo caso, prima del calcolo del carattere di controllo vengono effettuate le seguenti sostituzioni:

X Y Z
0 1 2

Ci sono molti calcolatori online che ti aiutano a ottenere il carattere di controllo, ma quanto tempo puoi scrivere quel codice? Scrivi un algoritmo (programma o funzione) che riceve un stringcon il numero DNI (che sarà sempre composto da 8 caratteri alfanumerici) e restituisce solo il singolo carattere di controllo calcolato e niente di più (viene accettata una nuova riga finale).

Appunti:

  • Il DNI è sempre scritto in maiuscolo, ma nel tuo algoritmo puoi scegliere l'input e l'output come maiuscoli o minuscoli, solo essere coerenti.
  • Nella vita reale, alcuni NIE emessi prima del 2008 hanno 8 cifre dopo il X, Yo Z, ma ai fini di questo gioco, puoi considerare che hanno 7 cifre come al giorno d'oggi.
  • Puoi considerare che la stringa di input avrà sempre 8 caratteri, ma se non sono nel formato "8 cifre" né nel formato "[XYZ] più 7 cifre", devi restituire un errore (a tua scelta) o semplicemente lanciare un'eccezione.

Casi test:

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>

Questo è , quindi può vincere il codice più breve per ogni lingua!



2
È davvero importante che il codice abbia un comportamento specifico sull'input non valido? Di solito le sfide qui non richiedono preoccupazioni per la gestione degli errori.
Greg Martin,

3
@GregMart. A mio avviso, volevo solo che il codice mostrasse un comportamento specifico sugli input degli errori, dato che di solito non è richiesto.
Charlie

In "dividi il numero per 23, prendi il resto dell'operazione", il termine corretto è resto ; il riposo è troppo colloquiale.
Locoluis,

2
@Locoluis in spagnolo diciamo resto , rendendo "riposo" un falso amico, quindi. Almeno non ho usato un termine sbagliato. :-) Grazie!
Charlie

Risposte:


11

Python 3 , 83 byte

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

Provalo online!

-5 grazie ad AlixEinsenhardt (dal 99 al 94). -1 grazie a JonathanAllan .


1
È possibile sostituire str('XYZ'.index(n[0]))da str(ord(n[0])-88)e salvare 5 byte
Alix Eisenhardt

1
@AlixEisenhardt Il suggerimento di cui sopra mi ha ispirato a cambiare la tecnica in una lambda, che alla fine ha salvato 10 byte.
Mr. Xcoder,

Salvare un byte sostituendolo -88con %4.
Jonathan Allan,

8

Haskell , 107 93 92 byte

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

Provalo online!


Qual è il comportamento sugli input non validi?
Charlie

Arresto anomalo del programma, ne ho aggiunto uno nell'esempio. (in pratica genera un'eccezione che nessuno cattura)
bartavelle

1
Ho aggiornato l'invio con la rilevazione delle eccezioni, in modo che tutti i test possano essere eseguiti.
bartavelle,

5

Pyth, 35 34 byte

Il codice contiene alcuni caratteri non stampabili, quindi ecco un xxdhexdump reversibile .

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

Utilizza caratteri minuscoli .

Provalo online. Suite di test.

Versione stampabile

@.P305777935990456506899534929G%ssXcz]1>3GU3 23

Spiegazione

  • cz]1divide l'ingresso in posizione 1, ad es . "y0000369"a ["y", "0000369"].
  • >3Gottiene gli ultimi 3 caratteri dell'alfabeto, "xyz".
  • U3ottiene l'intervallo [0, 3 [ , [0, 1, 2].
  • Xmappe xyzdi [0, 1, 2]nell'array diviso, ad esempio ["y", "0000369"]a [1, "0000369"]. Questo sostituisce il primo carattere, se presente xyz, lasciando intatta la coda di 7 caratteri poiché qualsiasi stringa di 7 caratteri non può essere uguale a un singolo carattere.
  • sunisce l'array con la stringa vuota, ad es . [1, "0000369"]a "10000369".
  • slancia questa stringa in numero intero, ad es . "10000369"in 10000369. Ciò genera un errore se nella stringa rimangono caratteri extra non numerici.
  • %... 23ottiene il valore modulo 23, ad esempio 10000369a 15.
  • C"... "converte la stringa binaria dalla base 256 all'intero (circa 3,06 × 10 26 ).
  • .P... Gottiene la permutazione dell'alfabeto con quell'indice.
  • @ ottiene il carattere corretto dalla permutazione.

4

MATL , 62 59 byte

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

L'errore per input non valido è A(I): index out of bounds(compilatore in esecuzione in Octave) o Index exceeds matrix dimensions(compilatore in esecuzione in Matlab).

Provalo online!

Spiegazione

'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

4

ES6, 83 82 81 byte

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

In azione!

Solo in maiuscolo, il codice di errore per i numeri non validi è undefined.

Un byte salvato grazie a Jonathan Allan.
Un altro byte salvato grazie a Shaggy.


Forse salvare un byte usando %4anziché -88.
Jonathan Allan,

Dovreste essere in grado di far cadere il 0da charCodeAt()troppo.
Shaggy,

3

Java 8, 154 145 104 byte

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

-9 byte grazie a @ OliverGrégoire .
-41 byte grazie a @ OliverGrégoire , prendendo l'input come char-array ( char[]).

Se l'input non è valido, fallirà con un java.lang.NumberFormatExceptiono java.lang.StringIndexOutOfBoundsException.

Spiegazione:

Provalo qui. (I casi di test non validi sono circondati da try-catch in modo che non si fermi al primo errore.)

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

1
Non hai bisogno |del regex. Inoltre int t=s.charAt(0)-88e t<0?t+40:tsi riserva un byte.
Olivier Grégoire,

1
Infine, puoi restituire un codice di errore. Decidi semplicemente che è 'a'o '0'o una lettera non maiuscola e restituiscilo invece di t/0e lanciando l'intero lotto char. Risparmieresti 7 byte in questo modo, immagino. Giocato a golf in questo modo , ottieni 145 byte.
Olivier Grégoire,

1
@ OlivierGrégoire Grazie! Ho la sensazione che sia ancora possibile usare un modo diverso di convalidare invece che .matchescon questa regex, tra l'altro. Ma forse mi sbaglio.
Kevin Cruijssen,

1
No, hai perfettamente ragione! È fattibile in questo modo: s->{s[0]-=s[0]<88?0:40;return"TRWAGMYFPDXBNJZSQVHLCKE".charAt(new Integer(new String(s))%23);}per soli 94 byte (con l' sessere a char[]): p
Olivier Grégoire,

1
O se vuoi essere completo sulla validazione: s[0]<88&s[0]>90per altri 8 byte.
Olivier Grégoire,



1

q / kdb +, 68 byte

Soluzione:

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

Esempi:

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"
" "

Spiegazione:

Se il primo carattere, x 0è nella stringa, "XYZ"allora asarà 0, 1o 2. Se il primo carattere non è nella stringa, alo sarà 3. Se aè inferiore a 3, si cambia il primo carattere per la stringa di un ( 0, 1o 2), altrimenti si cambia per il primo carattere (quindi non si fa effettivamente nulla). Questa stringa è lanciata su un long ( "J"$), che è quindi modcon 23 per dare il resto. Questo resto viene utilizzato per indicizzare nella tabella di ricerca.

{ "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

Appunti:

" "viene restituito negli scenari di errore, ciò perché il cast restituisce un valore nullo e l'indicizzazione in una stringa con indice null è un carattere vuoto. Potrei aggiungere 4 byte all'inizio ( "!"^) per rendere più ovvio che si era verificato un errore:

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

1

JavaScript (ES6), 121 byte

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")])



1

Ruggine, 206 byte

Non credo che la ruggine sia adatta per il golf del codice -_-

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))};

1

05AB1E , 41 40 39 byte

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

Accetta l'ingresso in minuscolo (per salvare 1 byte yay )

Provalo online!

Stampa l'input su STDERR se non è valido

Spiegazione

ć…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

0

Dyalog APL, 95 byte

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

Questo è un operatore monadico che accetta una stringa di caratteri come suo operando e restituisce il suo risultato.

FIXME non controlla il suo input. Non è correttamente giocato a golf.

Uso:

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

      OP '01234567'
L

      OP '00000010'
X
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.