Calculadora de caracteres de controle de cartão de identificação em espanhol

20

Este é um algoritmo muito, muito simples, que tenho certeza de que pode ser resolvido em muitas linguagens diferentes. Na Espanha, os cartões de identificação (conhecidos como DNI ) consistem em 8 números e um caractere de controle. O caractere de controle é calculado com o seguinte algoritmo: divida o número por 23, pegue o restante da operação e substitua-o por um caractere de acordo com esta tabela:

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 o DNI pertence a uma pessoa estrangeira a viver em Espanha, o primeiro dígito é alterado para X, You Ze é chamado de NIE . Nesse caso, as seguintes substituições são feitas antes de calcular o caractere de controle:

X Y Z
0 1 2

Existem muitas calculadoras on-line que ajudam a obter o caractere de controle, mas qual é a duração do código? Escreva um algoritmo (programa ou função) que receba um stringcom o número DNI (que sempre consistirá em 8 caracteres alfanuméricos) e retorne apenas o caractere de controle único calculado e nada mais (uma nova linha à direita é aceita).

Notas:

  • O DNI é sempre escrito em letras maiúsculas, mas em seu algoritmo você pode escolher a entrada e a saída em maiúsculas ou minúsculas, apenas seja consistente.
  • Na vida real, alguns NIEs emitidos antes de 2008 têm 8 dígitos após o X, You Z, mas, para os propósitos deste jogo, você pode considerar que eles têm 7 dígitos como têm atualmente.
  • Você pode considerar que a sequência de entrada sempre terá 8 caracteres, mas se não estiverem no formato "8 dígitos" nem no formato "[XYZ] mais 7 dígitos", será necessário retornar um erro (de sua escolha) ou apenas jogar uma exceção.

Casos de teste:

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 é o , portanto, pode ganhar o código mais curto para cada idioma!

Charlie
fonte
Sandbox .
Charlie
2
É realmente importante que o código tenha um comportamento específico na entrada inválida? Normalmente, os desafios aqui não exigem preocupação com o tratamento de erros.
Greg Martin
3
@GregMartin no meu ponto precisamente, eu só queria que o código mostrasse algum comportamento específico nas entradas de erro, pois geralmente não é necessário.
Charlie
Em "divida o número por 23, faça o resto da operação", o termo correto é o restante ; o resto é muito coloquial.
Locoluis
2
@Locoluis em espanhol, dizemos resto , fazendo com que "rest" seja um falso amigo. Pelo menos eu não usei um termo errado. :-) Obrigado!
307 Charlie

Respostas:

11

Python 3 , 83 bytes

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

Experimente online!

-5 graças a AlixEinsenhardt (de 99 a 94). -1 graças a JonathanAllan .

Mr. Xcoder
fonte
1
Você pode substituir str('XYZ'.index(n[0]))por str(ord(n[0])-88)e salvar 5 bytes
Alix Eisenhardt
1
@AlixEisenhardt A sugestão acima me inspirou a mudar a técnica para uma lambda, que eventualmente salvou 10 bytes.
Mr. Xcoder
Salve um byte substituindo -88por %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

Experimente online!

bartavelle
fonte
Qual é o comportamento em entradas inválidas?
Charlie
Eles vão travar o programa, eu adicionei um no exemplo. (na prática, ele gera uma excepção de que ninguém capturas)
bartavelle
1
Atualizei o envio com captura de exceção, para que todos os testes pudessem ser executados.
bartavelle
5

Pitão, 35 34 bytes

O código contém alguns caracteres não imprimíveis, então aqui está um xxdhexdump reversível .

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

Usos caracteres minúsculos .

Experimente online. Suíte de teste.

Versão imprimível

@.P305777935990456506899534929G%ssXcz]1>3GU3 23

Explicação

  • cz]1 divide a entrada na posição 1, por exemplo "y0000369" para ["y", "0000369"].
  • >3G obtém os três últimos caracteres do alfabeto, "xyz" ,.
  • U3obtém o intervalo [0, 3 [ , [0, 1, 2].
  • Xmapeia xyzpara [0, 1, 2]na matriz dividida, por exemplo, ["y", "0000369"]para[1, "0000369"] . Isso substitui o primeiro caractere, se for um deles xyz, mantendo intacto o final de 7 caracteres, pois qualquer sequência de 7 caracteres não pode ser igual a um único caractere.
  • s une a matriz à sequência vazia, por exemplo [1, "0000369"] para "10000369".
  • s lança essa string para inteiro, por exemplo "10000369" para 10000369. Isso gera um erro se algum caractere extra de não dígito for deixado na string.
  • %23Obtém o valor módulo 23, por exemplo10000369 para 15.
  • C""Converte a sequência binária da base 256 em número inteiro (cerca de 3,06 × 10 26 ).
  • .P...G Obtém a permutação do alfabeto com esse índice.
  • @ obtém o caractere correto da permutação.
PurkkaKoodari
fonte
4

MATL , 62 59 bytes

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

O erro para entrada inválida é A(I): index out of bounds(compilador em execução no Octave) ou Index exceeds matrix dimensions(compilador em execução no Matlab).

Experimente online!

Explicação

'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
fonte
4

ES6, 83 82 81 bytes

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

Em ação!

Apenas em maiúsculas, o código de erro para números inválidos é undefined.

Um byte economizado graças a Jonathan Allan.
Outro byte economizado graças a Shaggy.

2ndAttmt
fonte
Talvez salve um byte usando em %4vez de -88.
Jonathan Allan
Você deve ser capaz de largar a 0partir charCodeAt()também.
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 graças a @ OliverGrégoire .
-41 bytes graças a @ OliverGrégoire novamente, assumindo a entrada como um array de caracteres (char[] ).

Se a entrada for inválida, ela falhará com um java.lang.NumberFormatExceptionoujava.lang.StringIndexOutOfBoundsException .

Explicação:

Experimente aqui. (Os casos de teste inválidos são cercados por try-catch, para que não pare no primeiro erro.)

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
fonte
1
Você não precisa do |no regex. Também int t=s.charAt(0)-88& t<0?t+40:tlivre você um byte.
Olivier Grégoire
1
Finalmente, você pode retornar um código de erro. Apenas decida que é 'a'ou '0'não uma letra maiúscula e devolva-a em vez de t/0e convertendo o lote inteiro para char. Você economizaria 7 bytes dessa maneira, eu acho. Jogando golfe dessa maneira , você obtém 145 bytes.
Olivier Grégoire
1
@ OlivierGrégoire Obrigado! Tenho a sensação de que ainda é possível usar uma maneira diferente de validar em vez de .matchescom esse regex, btw. Mas talvez eu esteja enganado.
Kevin Cruijssen
1
Não, você está totalmente certo! É factível assim: s->{s[0]-=s[0]<88?0:40;return"TRWAGMYFPDXBNJZSQVHLCKE".charAt(new Integer(new String(s))%23);}por apenas 94 bytes (com sa char[]): p #
Olivier Grégoire
1
Ou se você deseja concluir a validação: s[0]<88&s[0]>90por mais 8 bytes.
Olivier Grégoire
2

PHP , 88 bytes

imprime 1 por erro

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

Experimente online!

Jörg Hülsermann
fonte
2

Geléia , 42 bytes

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

Experimente online!

Muito tempo, Jelly! Dennis está decepcionado com você! [citação necessária]

Erik, o Outgolfer
fonte
1

q / kdb +, 68 bytes

Solução:

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

Exemplos:

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

Explicação:

Se o primeiro caractere,, x 0estiver na sequência "XYZ", aserá 0, 1ou 2. Se o primeiro caractere não estiver na sequência, aserá 3. Se afor inferior a 3, trocamos o primeiro caractere para a cadeia de um ( 0, 1ou 2), caso contrário, vamos mudar para fora para o primeiro caractere (assim, efetivamente fazendo nada). Essa string é convertida em long ( "J"$), que é então modd com 23 para fornecer o restante. Esse restante é usado para indexar na tabela de pesquisa.

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

" "é retornado nos cenários de erro, isso ocorre porque a conversão retorna um nulo e a indexação em uma sequência no índice nulo é um caractere vazio. Eu poderia adicionar 4 bytes no início ( "!"^) para tornar mais óbvio que ocorreu um erro:

q){"!"^"TRWAGMYFPDXBNJZSQVHLCKE"("J"$$[3>a:"XYZ"?x 0;($)a;x 0],1_x)mod 23}"1231XX12"
"!"
rua
fonte
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")])

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

Japt , 50 bytes

Semelhante à maioria das outras abordagens.

Entrada e saída são minúsculas, saídas undefinedpara entrada inválida.

`tr°gmyfpdxbnjzsqvhlcke`g("xyz"øUg)?Uc %4+UÅ:U %23

Teste
todos os casos de teste válidos

Shaggy
fonte
1

Ferrugem, 206 bytes

Eu não acho que a ferrugem é adequada para o código de golfe -_-

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
fonte
1

05AB1E , 41 40 39 bytes

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

Leva a entrada em minúsculas (para salvar 1 byte yay )

Experimente online!

Imprime a entrada em STDERR se estiver malformada

Explicação

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

Dyalog APL, 95 bytes

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

Este é um operador monádico que aceita uma cadeia de caracteres como seu operando e retorna seu resultado.

FIXME não verifica sua entrada. Não é devidamente jogado.

Uso:

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

      OP '01234567'
L

      OP '00000010'
X
Locoluis
fonte