西班牙身份证控制字符计算器


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属于生活在西班牙的外籍人士,第一个数字更改为XYZ它被称为NIE。在这种情况下,在计算控制字符之前进行以下替换:

X Y Z
0 1 2

在线上有很多计算器可以帮助您获得控制字符,但是,您能编写多长时间的代码?编写一个算法(程序或函数),该算法将接收一个string带有DNI编号(将始终由8个字母数字字符组成)的a,并仅返回计算出的单个控制字符,仅返回一个(接受尾随换行符)。

笔记:

  • DNI始终以大写形式编写,但是在算法中,您可以选择输入和输出为大写或小写,只要保持一致即可。
  • 在现实生活中,2008年之前发行的某些NIE在XY或之后有8位数字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我们说Resto餐厅,使得“休息”假朋友,那么。至少我没有使用错误的术语。:-) 谢谢!
查理

Answers:


11

Python 3,83个字节

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

在线尝试!

-5感谢AlixEinsenhardt(从99到94)。-1感谢JonathanAllan


1
您可以替换str('XYZ'.index(n[0]))通过str(ord(n[0])-88)并保存5个字节
阿利克斯艾森哈特

1
@AlixEisenhardt上面的建议启发了我将技术更改为lambda,最终节省了10个字节。
Xcoder先生17年

替换-88为保存一个字节%4
乔纳森·艾伦

8

Haskell107 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字节

该代码包含一些不可打印的字符,因此这是一个可逆的xxd十六进制转储。

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]分割阵列中,例如["y", "0000369"][1, "0000369"]。如果第一个字符是xyz,则将替换第一个字符,同时保留7个字符的尾部,因为任何7个字符串都不能等于单个字符。
  • s加入与空字符串,例如数组[1, "0000369"]"10000369"
  • s把这个字符串到整数,例如"10000369"10000369。如果字符串中还剩下任何其他非数字字符,则会引发错误。
  • %... 23得到值模23,如1000036915
  • C""将二进制字符串从基数256转换为整数(大约3.06×10 26)。
  • .PG获取带有该索引的字母排列。
  • @ 从排列中获取正确的字符。

4

MATL62 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
乔纳森·艾伦

您应该能够删除0charCodeAt()了。
毛茸茸的

3

爪哇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。通过将输入作为字符数组(),再次
感谢@OliverGrégoire- 41字节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)-88t<0?t+40:t饶你一字节。
奥利维尔·格雷戈尔

1
最后,您可以返回错误代码。只需确定它是'a''0'任何非大写字母,然后将其返回,而不是t/0将全部转换为即可char。我想,这样可以节省7个字节。这样打高尔夫球,您将获得145个字节。
OlivierGrégoire'7

1
@OlivierGrégoire谢谢!我觉得仍然可以使用另一种验证方式来代替.matches正则表达式btw。但也许我弄错了。
凯文·克鲁伊森

1
不,您完全正确!这样做是可行的:s->{s[0]-=s[0]<88?0:40;return"TRWAGMYFPDXBNJZSQVHLCKE".charAt(new Integer(new String(s))%23);}仅94个字节(以sa表示char[]):p
OlivierGrégoire17年

1
或者,如果您想完成有关验证的内容,请:再s[0]<88&s[0]>90输入8个字节。
奥利维尔·格雷戈尔(OlivierGrégoire),



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",然后a012。如果第一个字符不在字符串中,a则将为3。如果a小于3,我们切换出第一个字符的字符串(012),否则我们切换出的第一个字符(从而有效地什么都不做)。该字符串被强制转换为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

笔记:

" "在错误情况下返回,这是因为强制类型转换返回null,而索引为null的字符串索引为空char。我可以在开始("!"^)处添加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

05AB1E41 40 39字节

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

发生在小写输入(保存1字节

在线尝试!

如果输入格式错误,则将其输出到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

Dyalog APL,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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.