Kalkulator znaków kontrolnych hiszpańskiego dowodu osobistego

20

To bardzo prosty algorytm, który z pewnością można rozwiązać w wielu różnych językach. W Hiszpanii dowody osobiste (znane jako DNI ) składają się z 8 cyfr i znaku kontrolnego. Znak kontrolny jest obliczany za pomocą następującego algorytmu: podziel liczbę przez 23, weź pozostałą część operacji i zastąp ją znakiem zgodnie z poniższą tabelą:

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

Jeśli DNI należy do osoby obcej mieszkającej w Hiszpanii, pierwsza cyfra zmienia się na X, Ylub Zi to nazywa się NIE . W takim przypadku przed obliczeniem znaku kontrolnego wprowadza się następujące podstawienia:

X Y Z
0 1 2

Istnieje wiele kalkulatorów online, które pomagają uzyskać znak kontrolny, ale jak krótkie jest napisanie tego kodu? Napisz algorytm (program lub funkcję), który otrzyma a stringz numerem DNI (który zawsze będzie się składał z 8 znaków alfanumerycznych) i zwróci tylko jeden obliczony znak kontrolny i nic więcej (nowa linia jest akceptowana).

Uwagi:

  • Nazwa DNI jest zawsze zapisywana wielkimi literami, ale w algorytmie możesz wybrać, czy dane wejściowe i wyjściowe mają być pisane wielkimi lub małymi literami, po prostu zachowaj spójność.
  • W rzeczywistości niektóre NIE wydane przed 2008 rokiem mają 8 cyfr po X, Ylub Z, ale dla celów tej gry można uznać, że mają 7 cyfr, tak jak obecnie.
  • Możesz wziąć pod uwagę, że ciąg wejściowy zawsze będzie miał 8 znaków, ale jeśli nie są one w formacie „8 cyfr” ani w formacie „[XYZ] plus 7 cyfr”, musisz zwrócić błąd (do wyboru) lub po prostu rzucić wyjątek.

Przypadki testowe:

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>

To jest , więc wygrywa najkrótszy kod dla każdego języka!

Charlie
źródło
Piaskownica .
Charlie,
2
Czy to naprawdę ważne, aby kod zachowywał się przy nieprawidłowym wprowadzaniu? Zazwyczaj wyzwania tutaj nie wymagają martwienia się o obsługę błędów.
Greg Martin
3
@GregMart W moim punkcie właśnie chciałem po prostu, aby kod pokazywał określone zachowanie na błędach, ponieważ zwykle nie jest to wymagane.
Charlie,
W „podziel liczbę przez 23, weź resztę operacji” poprawnym terminem jest reszta ; reszta jest zbyt potoczna.
Locoluis
2
@Locoluis po hiszpańsku mówimy resto , dzięki czemu „odpoczynek” jest fałszywym przyjacielem. Przynajmniej nie użyłem złego terminu. :-) Dziękuję Ci!
Charlie

Odpowiedzi:

11

Python 3 , 83 bajty

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

Wypróbuj online!

-5 dzięki AlixEinsenhardt (od 99 do 94). -1 dzięki JonathanAllan .

Pan Xcoder
źródło
1
Można zastąpić str('XYZ'.index(n[0]))przez str(ord(n[0])-88)i zaoszczędzić 5 bajtów
Alix Eisenhardt
1
@AlixEisenhardt Powyższa sugestia zainspirowała mnie do zmiany techniki na lambda, co ostatecznie pozwoliło zaoszczędzić 10 bajtów.
Pan Xcoder,
Zapisz bajt, zastępując -88go %4.
Jonathan Allan
8

Haskell , 107 93 92 bajty

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

Wypróbuj online!

bartavelle
źródło
Jakie zachowanie zachodzą przy nieprawidłowych danych wejściowych?
Charlie,
Zepsują program, dodałem jeden w przykładzie. (w praktyce rzuca wyjątek, że nikt nie łapie)
bartavelle,
1
Zaktualizowałem przesyłanie z wychwytywaniem wyjątków, aby wszystkie testy mogły zostać uruchomione.
bartavelle,
5

Pyth, 35 34 bajtów

Kod zawiera niektóre niedrukowalne znaki, więc oto odwracalny xxdzrzut heksowy.

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

Używa małych liter .

Wypróbuj online. Zestaw testowy.

Wersja do druku

@.P305777935990456506899534929G%ssXcz]1>3GU3 23

Wyjaśnienie

  • cz]1dzieli wejście w pozycji 1, np . "y0000369"na ["y", "0000369"].
  • >3Gdostaje 3 ostatnie znaki alfabetu "xyz".
  • U3pobiera zakres [0, 3 [ , [0, 1, 2].
  • Xodwzorowuje xyzna [0, 1, 2]w podzielonej tablicy, np . ["y", "0000369"]na [1, "0000369"]. Zastępuje to pierwszy znak, jeśli jest jednym z nich xyz, pozostawiając ogon 7 znaków nietkniętych, ponieważ każdy ciąg 7 znaków nie może być równy jednemu znakowi.
  • słączy tablicę z pustym łańcuchem, np . [1, "0000369"]do "10000369".
  • srzutuje ten ciąg na liczbę całkowitą, np . "10000369"na 10000369. Zgłasza to błąd, jeśli w łańcuchu pozostaną jakieś dodatkowe znaki inne niż cyfry.
  • %... 23Pobiera wartość modulo 23, na przykład 10000369do 15.
  • C""Konwertuje ciąg binarny z bazy 256 na liczbę całkowitą (około 3,06 × 10 26 ).
  • .PGPobiera permutację alfabetu z tym indeksem.
  • @ pobiera prawidłowy znak z permutacji.
PurkkaKoodari
źródło
4

MATL , 62 59 bajtów

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

Błąd niepoprawnego wejścia to A(I): index out of bounds(kompilator działający w Octave) lub Index exceeds matrix dimensions(kompilator działający w Matlab).

Wypróbuj online!

Wyjaśnienie

'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
źródło
4

ES6, 83 82 81 bajtów

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

W akcji!

Tylko wielkie litery, kod błędu dla nieprawidłowych liczb to undefined.

Jeden bajt zaoszczędzony dzięki Jonathanowi Allanowi.
Kolejny bajt uratowany dzięki Kudłatemu.

2ndAttmt
źródło
Może %4zamiast tego zaoszczędzić bajt -88.
Jonathan Allan
Powinieneś być w stanie upuść 0od charCodeAt()zbyt.
Kudłaty
3

Java 8, 154 145 104 bajtów

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

-9 bajtów dzięki @ OliverGrégoire .
-41 bajtów dzięki @ OliverGrégoire ponownie, przyjmując dane wejściowe jako char-array ( char[]).

Jeśli dane wejściowe są niepoprawne, albo nie powiedzie się za pomocą a, java.lang.NumberFormatExceptionalbo java.lang.StringIndexOutOfBoundsException.

Wyjaśnienie:

Wypróbuj tutaj. (Nieprawidłowe przypadki testowe są otoczone przez try-catch, więc nie kończy się na pierwszym błędzie).

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
źródło
1
Nie potrzebujesz |wyrażenia regularnego. Również int t=s.charAt(0)-88i t<0?t+40:toszczędzam bajt.
Olivier Grégoire
1
Na koniec możesz zwrócić kod błędu. Po prostu zdecyduj, że to'a' lub '0'czy jakikolwiek zakaz pisania wielkimi literami, i powrócić że zamiast t/0i oddające cały los char. W ten sposób zaoszczędziłbyś 7 bajtów. Gra w golfa w ten sposób , masz 145 bajtów.
Olivier Grégoire,
1
@ OlivierGrégoire Thanks! Mam wrażenie, że nadal można użyć innego sposobu sprawdzania poprawności zamiast .matchestego wyrażenia regularnego, btw. Ale może się mylę.
Kevin Cruijssen
1
Nie, masz całkowitą rację! Można to zrobić tak: s->{s[0]-=s[0]<88?0:40;return"TRWAGMYFPDXBNJZSQVHLCKE".charAt(new Integer(new String(s))%23);}tylko dla 94 bajtów (zs byciu a char[]): p
Olivier Grégoire
1
Lub jeśli chcesz być kompletny na temat sprawdzania poprawności: s[0]<88&s[0]>90 o 8 kolejnych bajtów.
Olivier Grégoire
2

PHP , 88 bajtów

drukuje 1 dla błędu

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

Wypróbuj online!

Jörg Hülsermann
źródło
2

Galaretka , 42 bajty

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

Wypróbuj online!

Za długo, galaretko! Dennis jest z ciebie rozczarowany! [wymagany cytat]

Erik the Outgolfer
źródło
1

q / kdb +, 68 bajtów

Rozwiązanie:

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

Przykłady:

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

Wyjaśnienie:

Jeśli pierwszy znak,, x 0jest w ciągu, "XYZ"to abędzie 0, 1lub 2. Jeśli pierwszego znaku nie ma w ciągu, abędzie 3. Jeśli ajest mniejsze niż 3, zamieniamy pierwszy znak na ciąg znaków ( 0, 1lub 2), w przeciwnym razie zamieniamy na pierwszy znak (w ten sposób skutecznie nic nie robiąc). Ciąg ten jest rzutowany na long ( "J"$), który jest następnie modoznaczony jako 23, dając resztę. Ta reszta służy do indeksowania w tabeli odnośników.

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

Uwagi:

" "jest zwracany w scenariuszach błędów, ponieważ rzutowanie zwraca wartość NULL, a indeksowanie w łańcuch o wartości NULL jest pustym znakiem. Mógłbym dodać 4 bajty na początku ( "!"^), aby było bardziej oczywiste, że wystąpił błąd:

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

JavaScript (ES6), 121 bajtów

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

Евгений Новиков
źródło
1

Rdza, 206 bajtów

Nie sądzę, że rdza nadaje się do gry w golfa kodowego -_-

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
źródło
1

05AB1E , 41 40 39 bajtów

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

Wprowadza dane małymi literami (aby zaoszczędzić 1 bajt yay )

Wypróbuj online!

Drukuje dane wejściowe do STDERR, jeśli są zniekształcone

Wyjaśnienie

ć…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
źródło
0

Dyalog APL, 95 bajtów

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

Jest to operator monadyczny, który akceptuje ciąg znaków jako operand i zwraca wynik.

FIXME nie sprawdza danych wejściowych. To nie jest właściwie gra w golfa.

Stosowanie:

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

      OP '01234567'
L

      OP '00000010'
X
Locoluis
źródło