Испанский калькулятор контрольных символов ID-карты


20

Это очень очень простой алгоритм, который, я уверен, может быть решен во многих разных языках. В Испании идентификационные карты (известные как DNI ) состоят из 8 цифр и контрольного символа. Управляющий символ рассчитывается по следующему алгоритму: разделите число на 23, возьмите оставшуюся часть операции и замените ее символом в соответствии с этой таблицей:

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

Если DNI принадлежит иностранному лицу , проживающему в Испании, первая цифра меняется на X, Yили , Zи это называется NIE . В этом случае перед вычислением контрольного символа делаются следующие замены:

X Y Z
0 1 2

В сети есть множество калькуляторов, которые помогают вам получить управляющий символ, но как быстро вы можете написать этот код? Напишите алгоритм (программу или функцию), который получает a stringс номером DNI (который всегда будет состоять из 8 буквенно-цифровых символов) и возвращает только один вычисленный управляющий символ и ничего более (завершающий перевод строки принимается).

Примечания:

  • DNI всегда пишется в верхнем регистре, но в вашем алгоритме вы можете выбрать ввод и вывод в верхнем или нижнем регистре, просто быть последовательными.
  • В реальной жизни некоторые NIE, выпущенные до 2008 года, имеют 8 цифр после X, Yили Z, но для целей этой игры вы можете считать, что они имеют 7 цифр, как в настоящее время.
  • Вы можете считать, что входная строка всегда будет иметь 8 символов, но если они не в формате «8 цифр» или в формате «[XYZ] плюс 7 цифр», вы должны вернуть ошибку (по вашему выбору) или просто бросить исключение.

Тестовые случаи:

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>

Это , поэтому победит самый короткий код для каждого языка!



2
Действительно ли важно, чтобы код имел определенное поведение при неверном вводе? Обычно проблемы здесь не требуют беспокойства об обработке ошибок.
Грег Мартин

3
@GregMart, с моей точки зрения, я просто хотел, чтобы код показывал определенное поведение при вводе ошибок, поскольку это обычно не требуется.
Чарли

В «разделите число на 23, возьмите оставшуюся часть операции», правильный термин - остаток ; отдых слишком разговорный.
Locoluis

2
@Locoluis по-испански, мы говорим « ресто» , делая «отдых» ложным другом. По крайней мере, я не использовал неправильный термин. :-) Спасибо!
Чарли

Ответы:


11

Python 3 , 83 байта

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

Попробуйте онлайн!

-5 благодаря АликсЭйнсенхардту (с 99 до 94). -1 спасибо Джонатану Аллану .


1
Вы можете заменить str('XYZ'.index(n[0]))на str(ord(n[0])-88)и сохранить 5 байт
Аликс Eisenhardt

1
@AlixEisenhardt Приведенное выше предложение вдохновило меня изменить технику на лямбду, которая в итоге сэкономила 10 байт.
Мистер Кскодер

Сохраните байт, заменив -88на %4.
Джонатан Аллан

8

Haskell , 107 93 92 байта

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

Попробуйте онлайн!


Каково поведение на неверных входах?
Чарли

Они потерпят крах программы, я добавил один в примере. (на практике это исключение, которое никто не ловит)
bartavelle

1
Я обновил представление с перехватом исключений, чтобы можно было запустить все тесты.
Bartavelle

5

Pyth, 35 34 байта

Код содержит некоторые непечатаемые символы, так что здесь есть обратимый xxdhexdump.

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

Используются строчные буквы .

Попробуйте онлайн. Тестирование.

Версия для печати

@.P305777935990456506899534929G%ssXcz]1>3GU3 23

объяснение

  • cz]1разбивает ввод в позиции 1, например, "y0000369"на ["y", "0000369"].
  • >3Gполучает последние 3 символа алфавита "xyz".
  • U3получает диапазон [0, 3 [ , [0, 1, 2].
  • Xотображается xyzна [0, 1, 2]в массиве split, например, ["y", "0000369"]на [1, "0000369"]. Это заменяет первый символ, если он является одним из xyz, оставляя хвост из 7 символов нетронутым, поскольку любая строка из 7 символов не может быть равна одному символу.
  • sобъединяет массив с пустой строкой, например, [1, "0000369"]в "10000369".
  • sпреобразует эту строку в целое число, например, "10000369"в 10000369. Это выдает ошибку, если в строке остаются лишние нецифровые символы.
  • %23Получает значение по модулю 23, например, 10000369в 15.
  • C""Преобразует двоичную строку из базы 256 в целое число (около 3,06 × 10 26 ).
  • .P... Gполучает перестановку алфавита с этим индексом.
  • @ получает правильный характер от перестановки.

4

MATL , 62 59 байт

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

Ошибка для неверного ввода: A(I): index out of bounds(компилятор работает в Octave) или Index exceeds matrix dimensions(компилятор работает в Matlab).

Попробуйте онлайн!

объяснение

'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 байт

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

В бою!

Только в верхнем регистре, код ошибки для недопустимых номеров undefined.

Один байт спасен благодаря Джонатану Аллану.
Еще один байт сохранен благодаря Shaggy.


Может быть, сохранить байт, %4а не -88.
Джонатан Аллан

Вы должны быть в состоянии отказаться 0от charCodeAt()тоже.
Лохматый

3

Java 8 154 145 104 байта

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

-9 байт благодаря @ OliverGrégoire .
-41 байт благодаря @ OliverGrégoire снова, принимая входные данные как массив символов ( char[]).

Если ввод неверен, он либо потерпит неудачу с помощью java.lang.NumberFormatExceptionили java.lang.StringIndexOutOfBoundsException.

Объяснение:

Попробуй это здесь. (Недопустимые тестовые примеры окружены try-catch, поэтому он не останавливается при первой ошибке.)

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
Вам не нужно |в регулярном выражении. Также int t=s.charAt(0)-88и t<0?t+40:tсэкономить вам байт.
Оливье Грегуар

1
Наконец, вы можете вернуть код ошибки. Просто решите , что это 'a'или '0'или любой не заглавная буква, и вернуться , что вместо того , чтобы t/0и литье все много char. Думаю, вы бы сэкономили 7 байтов таким образом. Таким образом , вы получаете 145 байтов.
Оливье Грегуар

1
@ OlivierGrégoire Спасибо! У меня есть ощущение, что все еще возможно использовать другой способ проверки вместо .matchesэтого регулярного выражения, кстати. Но, возможно, я ошибаюсь.
Кевин Круйссен

1
Нет, ты совершенно прав! Это выполнимо так: s->{s[0]-=s[0]<88?0:40;return"TRWAGMYFPDXBNJZSQVHLCKE".charAt(new Integer(new String(s))%23);}всего за 94 байта (при этом sбыть char[]): p
Оливье Грегуар

1
Или, если вы хотите закончить проверку: еще s[0]<88&s[0]>908 байтов.
Оливье Грегуар



1

q / kdb +, 68 байт

Решение:

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

Примеры:

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

Объяснение:

Если первый символ, x 0находится в строке, "XYZ"то aбудет 0, 1или 2. Если первого символа нет в строке, то aбудет 3. Если aменьше , чем 3, мы переходим из первого символа для строки а ( 0, 1или 2), в противном случае мы включаем за первый символ (таким образом , эффективно ничего не делать). Эта строка приведена к long ( "J"$), который затем modс 23 возвращает остаток. Этот остаток используется для индексации в таблице поиска.

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

Примечания:

" "возвращается в сценариях ошибок, это потому, что приведение возвращает ноль, а индексирование в строку с индексом ноль - пустой символ. Я мог бы добавить 4 байта в начало ( "!"^), чтобы сделать более очевидным, что произошла ошибка:

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

1

JavaScript (ES6), 121 байт

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

Ржавчина, 206 байт

Я не думаю, что ржавчина хорошо подходит для игры в гольф.

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 байт

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

Принимает ввод в нижнем регистре (чтобы сохранить 1 байт yay )

Попробуйте онлайн!

Печатает ввод в STDERR, если он искажен

объяснение

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

Дьялог АПЛ, 95 байт

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

Это монадический оператор, который принимает символьную строку в качестве своего операнда и возвращает ее результат.

FIXME он не проверяет свой ввод. Это не правильно гольф.

Использование:

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

      OP '01234567'
L

      OP '00000010'
X
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.