เครื่องคิดเลขการควบคุมบัตรสเปน 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 เขียนเป็นตัวพิมพ์ใหญ่เสมอ แต่ในอัลกอริทึมของคุณคุณสามารถเลือกอินพุตและเอาต์พุตให้เป็นตัวพิมพ์ใหญ่หรือตัวพิมพ์เล็กได้อย่างสอดคล้องกัน
  • ในชีวิตจริง NIEs บางส่วนที่ออกก่อน 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>

นี่คือดังนั้นอาจเป็นรหัสที่สั้นที่สุดสำหรับแต่ละภาษาที่ชนะ!


Sandbox
Charlie

2
เป็นสิ่งสำคัญหรือไม่ที่รหัสมีลักษณะการทำงานเฉพาะกับอินพุตที่ไม่ถูกต้อง โดยทั่วไปความท้าทายที่นี่ไม่จำเป็นต้องกังวลเกี่ยวกับการจัดการข้อผิดพลาด
Greg Martin

3
@ GregMart ในจุดของฉันอย่างแม่นยำฉันแค่ต้องการให้โค้ดแสดงพฤติกรรมบางอย่างเกี่ยวกับอินพุตที่ผิดพลาดเนื่องจากไม่จำเป็นต้องใช้
Charlie

ใน“แบ่งจำนวนโดย 23 ใช้เวลาที่เหลือของการดำเนินการ” คำที่ถูกต้องคือเหลือ ; ส่วนที่เหลือเป็นภาษาพูดมากเกินไป
Locoluis

2
@ Locoluis ในภาษาสเปนเราพูดว่าrestoทำให้ "พักผ่อน" เป็นเพื่อนเท็จแล้ว อย่างน้อยฉันก็ไม่ได้ใช้คำผิด :-) ขอขอบคุณ!
Charlie

คำตอบ:


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 ไบต์
Alix Eisenhardt

1
@AlixEisenhardt ข้อเสนอแนะด้านบนเป็นแรงบันดาลใจให้ฉันเปลี่ยนเทคนิคเป็นแลมบ์ดาซึ่งในที่สุดก็ประหยัด 10 ไบต์
Mr. Xcoder

บันทึกไบต์โดยการแทนที่ด้วย-88 %4
Jonathan Allan

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

ลองออนไลน์!


พฤติกรรมของอินพุตที่ไม่ถูกต้องคืออะไร
Charlie

พวกเขาจะผิดพลาดโปรแกรมฉันเพิ่มหนึ่งในตัวอย่าง (ในทางปฏิบัติมันมีข้อยกเว้นที่ไม่มีใครจับ)
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]ในอาร์เรย์แยกเช่นการ["y", "0000369"] [1, "0000369"]สิ่งนี้จะแทนที่ตัวอักษรตัวแรกหากเป็นตัวอักษรตัวใดตัวหนึ่งxyzในขณะที่ปล่อยส่วนท้ายของอักขระ 7 ตัวที่ไม่ถูกแตะต้องเนื่องจากสตริงอักขระ 7 ตัวใด ๆ จะต้องไม่เท่ากับอักขระตัวเดียว
  • sร่วมอาร์เรย์กับสตริงที่ว่างเปล่าเช่นการ[1, "0000369"]"10000369"
  • sดุจสายนี้เป็นจำนวนเต็มเช่นการ"10000369" 10000369สิ่งนี้จะโยนข้อผิดพลาดหากมีอักขระที่ไม่ใช่ตัวเลขพิเศษเหลืออยู่ในสตริง
  • %... 23ได้รับค่าโมดูโล 23 เช่นการ1000036915
  • 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(คอมไพเลอร์ทำงานในคู่) หรือ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ตัวพิมพ์ใหญ่เท่านั้นรหัสข้อผิดพลาดสำหรับตัวเลขที่ไม่ถูกต้อง

บันทึกหนึ่งไบต์ต้องขอบคุณ Jonathan Allan
ไบต์อื่นได้รับการบันทึกต้องขอบคุณ Shaggy


บางทีบันทึกไบต์ใช้มากกว่า%4 -88
Jonathan Allan

คุณควรจะสามารถที่จะลด0จากcharCodeAt()เกินไป
Shaggy

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-array ( char[])

หากใส่ไม่ถูกต้องก็อาจจะล้มเหลวด้วยหรือjava.lang.NumberFormatExceptionjava.lang.StringIndexOutOfBoundsException

คำอธิบาย:

ลองที่นี่ (กรณีทดสอบที่ไม่ถูกต้องถูกล้อมรอบด้วยลองจับดังนั้นจึงไม่หยุดที่ข้อผิดพลาดแรก)

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
คุณไม่ต้องการ|ใน regex นอกจากนี้ยังint t=s.charAt(0)-88และt<0?t+40:tอะไหล่คุณไบต์
Olivier Grégoire

1
ในที่สุดคุณสามารถส่งคืนรหัสข้อผิดพลาด เพียงแค่ตัดสินใจว่ามันเป็น'a'หรือ'0'หรืออักษรตัวพิมพ์ใหญ่ใด ๆ ที่ไม่ใช่และกลับที่แทนและออกเสียงจำนวนมากทั้งในการt/0 charฉันจะประหยัดได้ 7 ไบต์ด้วยวิธีนี้ฉันเดา วิธีนี้คุณจะได้รับ 145 ไบต์
Olivier Grégoire

1
@ OlivierGrégoireขอบคุณ! ฉันรู้สึกว่ามันยังคงเป็นไปได้ที่จะใช้วิธีการตรวจสอบที่แตกต่างกันแทนที่จะ.matchesใช้ regex นี้ btw แต่บางทีฉันเข้าใจผิด
Kevin Cruijssen

1
ไม่คุณพูดถูก! มันเป็นไปได้เช่นนี้: s->{s[0]-=s[0]<88?0:40;return"TRWAGMYFPDXBNJZSQVHLCKE".charAt(new Integer(new String(s))%23);}เพียง 94 ไบต์ (ด้วยsการเป็นchar[]): p
Olivier Grégoire

1
หรือถ้าคุณต้องการที่จะเสร็จสมบูรณ์เกี่ยวกับการตรวจสอบ: s[0]<88&s[0]>90สำหรับอีก 8 ไบต์
Olivier Gré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"แล้วaจะ0, หรือ1 2ถ้าตัวอักษรตัวแรกที่ไม่ได้อยู่ในสายแล้วจะa 3ถ้าaน้อยกว่า 3, เราเปลี่ยนจากตัวอักษรตัวแรกสำหรับสตริงของ (คน0, 1หรือ2) มิฉะนั้นเราสลับออกมาเป็นตัวอักษรตัวแรก (จึงมีประสิทธิภาพทำอะไร) สตริงนี้จะถูกส่งไปยังความยาว ( "J"$) ซึ่งก็คือmod23 ด้วยเพื่อให้ส่วนที่เหลือ ส่วนที่เหลือนี้ใช้เพื่อจัดทำดัชนีลงในตารางการค้นหา

{ "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 และการทำดัชนีลงในสตริงที่ index null เป็นอักขระว่าง ฉันสามารถเพิ่ม 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

Japt , 50 ไบต์

คล้ายกับวิธีอื่น ๆ ส่วนใหญ่

อินพุตและเอาต์พุตเป็นตัวพิมพ์เล็กและเอาต์พุตundefinedสำหรับอินพุตไม่ถูกต้อง

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

ทดสอบ
ทดสอบกรณีทดสอบที่ใช้ได้ทั้งหมด


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

Dyalog APL ขนาด 95 ไบต์

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

นี่คือตัวดำเนินการ monadic ที่ยอมรับสตริงอักขระเป็นตัวถูกดำเนินการและส่งกลับผลลัพธ์

FIXMEไม่ตรวจสอบอินพุต มันไม่ได้เล่นกอล์ฟอย่างถูกต้อง

การใช้งาน:

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

      OP '01234567'
L

      OP '00000010'
X
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.