Calculatrice de caractères de contrôle de carte d'identité espagnole

20

Il s'agit d'un algorithme très très simple, qui, j'en suis sûr, peut être résolu dans de nombreuses langues différentes. En Espagne, les cartes d'identité (appelées DNI ) se composent de 8 chiffres et d'un caractère de contrôle. Le caractère de contrôle est calculé avec l'algorithme suivant: divisez le nombre par 23, prenez le reste de l'opération et remplacez-le par un caractère selon ce tableau:

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 le DNI appartient à une personne étrangère vivant en Espagne, le premier chiffre est changé X, You Zil est appelé NIE . Dans ce cas, les substitutions suivantes sont effectuées avant de calculer le caractère de contrôle:

X Y Z
0 1 2

Il existe de nombreuses calculatrices en ligne qui vous aident à obtenir le caractère de contrôle, mais combien de temps pouvez-vous écrire ce code? Écrivez un algorithme (programme ou fonction) qui reçoit un stringavec le numéro DNI (qui sera toujours composé de 8 caractères alphanumériques) et ne renvoie que le seul caractère de contrôle calculé et rien de plus (une nouvelle ligne de fin est acceptée).

Remarques:

  • Le DNI est toujours écrit en majuscules, mais dans votre algorithme, vous pouvez choisir l'entrée et la sortie en majuscules ou en minuscules, soyez juste cohérent.
  • Dans la vraie vie, certains NPI émis avant 2008 ont 8 chiffres après la X, You Z, mais pour les besoins de ce jeu, vous pouvez considérer qu'ils ont 7 chiffres car ils ont de nos jours.
  • Vous pouvez considérer que la chaîne d'entrée aura toujours 8 caractères, mais s'ils ne sont pas au format "8 chiffres" ni au format "[XYZ] plus 7 chiffres", vous devez renvoyer une erreur (de votre choix) ou simplement jeter une exception.

Cas de 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>

C'est du , alors le code le plus court pour chaque langue peut gagner!

Charlie
la source
Sandbox .
Charlie
2
Est-il vraiment important que le code ait un comportement spécifique sur une entrée invalide? Habituellement, les défis ici ne nécessitent pas de se soucier du traitement des erreurs.
Greg Martin
3
@GregMartin mon point précisément, je voulais juste que le code montre un comportement spécifique sur les entrées d'erreur car il n'est généralement pas requis.
Charlie
Dans «divisez le nombre par 23, prenez le reste de l'opération», le terme correct est le reste ; le reste est trop familier.
Locoluis
2
@Locoluis en espagnol, nous disons resto , faisant de "repos" un faux ami, alors. Au moins, je n'ai pas utilisé un mauvais terme. :-) Merci!
Charlie

Réponses:

11

Python 3 , 83 octets

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

Essayez-le en ligne!

-5 grâce à AlixEinsenhardt (de 99 à 94). -1 merci à JonathanAllan .

M. Xcoder
la source
1
Vous pouvez remplacer str('XYZ'.index(n[0]))par str(ord(n[0])-88)et économiser 5 octets
Alix Eisenhardt
1
@AlixEisenhardt La suggestion ci-dessus m'a inspiré pour changer la technique en lambda, qui a finalement sauvé 10 octets.
M. Xcoder
Enregistrez un octet en le remplaçant -88par %4.
Jonathan Allan
8

Haskell , 107 93 92 octets

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

Essayez-le en ligne!

Bartavelle
la source
Quel est le comportement sur les entrées invalides?
Charlie
Ils vont planter le programme, j'en ai ajouté un dans l'exemple. (en pratique, il lève une exception que personne n'attrape)
bartavelle
1
J'ai mis à jour la soumission avec capture d'exception, afin que tous les tests puissent être exécutés.
bartavelle
5

Pyth, 35 34 octets

Le code contient des caractères non imprimables, voici donc un xxdvidage hexadécimal réversible .

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

Utilise des caractères minuscules .

Essayez-le en ligne. Suite de tests.

Version imprimable

@.P305777935990456506899534929G%ssXcz]1>3GU3 23

Explication

  • cz]1divise l'entrée à la position 1, par exemple "y0000369"vers ["y", "0000369"].
  • >3Gobtient les 3 derniers caractères de l'alphabet, "xyz".
  • U3obtient la plage [0, 3 [ , [0, 1, 2].
  • X Plans xyz à [0, 1, 2]dans le tableau fractionné, par exemple ["y", "0000369"]à [1, "0000369"]. Cela remplace le premier caractère s'il en est un xyz, tout en laissant la queue de 7 caractères intacte car aucune chaîne de 7 caractères ne peut être égale à un seul caractère.
  • sjoint le tableau avec la chaîne vide, par exemple [1, "0000369"]à "10000369".
  • sconvertit cette chaîne en entier, par exemple "10000369"en 10000369. Cela génère une erreur s'il reste des caractères non numériques supplémentaires dans la chaîne.
  • %23Obtient la valeur modulo 23, par ex.10000369 pour 15.
  • C""Convertit la chaîne binaire de la base 256 en entier (environ 3,06 × 10 26 ).
  • .PG Obtient la permutation de l'alphabet avec cet index.
  • @ obtient le caractère correct de la permutation.
PurkkaKoodari
la source
4

MATL , 62 59 octets

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

L'erreur pour une entrée non valide est A(I): index out of bounds(compilateur exécuté dans Octave) ouIndex exceeds matrix dimensions (compilateur fonctionnant dans Matlab).

Essayez-le en ligne!

Explication

'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
la source
4

ES6, 83 82 81 octets

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

En action!

Uniquement en majuscules, le code d'erreur pour les numéros invalides est undefined.

Un octet sauvé grâce à Jonathan Allan.
Un autre octet enregistré grâce à Shaggy.

2ndAttmt
la source
Peut-être enregistrer un octet en utilisant %4plutôt que -88.
Jonathan Allan
Vous devriez être en mesure de laisser tomber le 0de charCodeAt()trop.
Shaggy
3

Java 8, 154 145 104 octets

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

-9 octets grâce à @ OliverGrégoire .
-41 octets grâce à @ OliverGrégoire à nouveau, en prenant l'entrée comme un tableau de caractères (char[] ).

Si l'entrée n'est pas valide, elle échouera avec un java.lang.NumberFormatExceptionoujava.lang.StringIndexOutOfBoundsException .

Explication:

Essayez-le ici. (Les cas de test non valides sont entourés de try-catch pour ne pas s'arrêter à la première erreur.)

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
la source
1
Vous n'avez pas besoin de |dans l'expression régulière. Aussi int t=s.charAt(0)-88& t<0?t+40:tvous épargner un octet.
Olivier Grégoire
1
Enfin, vous pouvez renvoyer un code d'erreur. Il suffit de décider qu'il est 'a'ou '0'ou une lettre non majuscule et revenir qu'au lieu de t/0et jeter le tout à char. Vous économisez 7 octets de cette façon, je suppose. Golfé de cette façon , vous obtenez 145 octets.
Olivier Grégoire
1
@ OlivierGrégoire Merci! J'ai le sentiment qu'il est toujours possible d'utiliser une manière différente de valider plutôt .matchesqu'avec cette expression régulière, btw. Mais je me trompe peut-être.
Kevin Cruijssen
1
Non, tu as tout à fait raison! C'est faisable comme ça: s->{s[0]-=s[0]<88?0:40;return"TRWAGMYFPDXBNJZSQVHLCKE".charAt(new Integer(new String(s))%23);}pour seulement 94 octets (avec sun a char[]): p
Olivier Grégoire
1
Ou si vous voulez être complet sur la validation: s[0]<88&s[0]>90pour 8 octets supplémentaires.
Olivier Grégoire
2

PHP , 88 octets

imprime 1 pour une erreur

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

Essayez-le en ligne!

Jörg Hülsermann
la source
2

Gelée , 42 octets

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

Essayez-le en ligne!

Trop longtemps, Jelly! Dennis est déçu de toi! [citation requise]

Erik le Outgolfer
la source
1

q / kdb +, 68 octets

Solution:

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

Exemples:

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

Explication:

Si le premier caractère,, x 0est dans la chaîne, "XYZ"alors asera 0, 1ou 2. Si le premier caractère n'est pas dans la chaîne, alors le asera 3. Si aest inférieur à 3, nous commutons le premier caractère pour la chaîne d'un ( 0, 1ou 2), sinon nous commutons pour le premier caractère (donc ne faisant rien). Cette chaîne est convertie en un long ( "J"$), qui est alors mod«d» avec 23 pour donner le reste. Ce reste est utilisé pour indexer dans la table de recherche.

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

Remarques:

" "est retourné dans les scénarios d'erreur, cela est dû au fait que le transtypage renvoie une valeur null et que l'indexation dans une chaîne à l'index null est un caractère vide. J'ai pu ajouter 4 octets au début ( "!"^) pour rendre plus évidente qu'une erreur s'était produite:

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

JavaScript (ES6), 121 octets

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

Евгений Новиков
la source
1

Rouille, 206 octets

Je ne pense pas que la rouille soit bien adaptée au golf à code -_-

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
la source
1

05AB1E , 41 40 39 octets

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

Prend l'entrée en minuscules (pour économiser 1 octet oui )

Essayez-le en ligne!

Imprime l'entrée dans STDERR si elle est mal formée

Explication

ć…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
la source
0

Dyalog APL, 95 octets

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

Il s'agit d'un opérateur monadique qui accepte une chaîne de caractères comme opérande et renvoie son résultat.

RÉPARE-MOI il ne vérifie pas son entrée. Ce n'est pas bien joué.

Usage:

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

      OP '01234567'
L

      OP '00000010'
X
Locoluis
la source