9
\$\begingroup\$

Validate a codice fiscale

Every Italian resident/citizen is given a 16-character alphanumeric codice fiscale

Challenge

The final letter is a check code, which is calculated as follows :

  • Characters of the code are split up into even and odd character according to their positions (check letter excluded)
  • Both sets are replaced according to the following tables :
ODD CHARACTERS (1st, 3rd...)
Character Value Character Value Character Value Character Value
0 1 9 21 I 19 R 8
1 0 A 1 J 21 S 12
2 5 B 0 K 2 T 14
3 7 C 5 L 4 U 16
4 9 D 7 M 18 V 10
5 13 E 9 N 20 W 22
6 15 F 13 O 11 X 25
7 17 G 15 P 3 Y 24
8 19 H 17 Q 6 Z 23
EVEN CHARACTERS (2nd, 4th...)
Character Value Character Value Character Value Character Value
0 0 9 9 I 8 R 17
1 1 A 0 J 9 S 18
2 2 B 1 K 10 T 19
3 3 C 2 L 11 U 20
4 4 D 3 M 12 V 21
5 5 E 4 N 13 W 22
6 6 F 5 O 14 X 23
7 7 G 6 P 15 Y 24
8 8 H 7 Q 16 Z 25
  • Sum both sets together
  • Get the remainder of sum/26 and replace according to the table
Remainder Letter Remainder Letter Remainder Letter Remainder Letter
0 A 7 H 14 O 21 V
1 B 8 I 15 P 22 W
2 C 9 J 16 Q 23 X
3 D 10 K 17 R 24 Y
4 E 11 L 18 S 25 Z
5 F 12 M 19 T
6 G 13 N 20 U

Input

A 16-character codice fiscale in the XXXXXX00X00X000X form.

Assume the check letter will always be a letter

Output

Is the Codice Fiscale valid (the language truthy value) or not (language falsy value)?

For the purpose of the challenge, we consider a codice fiscale to be valid if the calculated check letter corresponds with the input's check letter.

Examples

TMDVSZ30T13L528J -> true
NWWFBE83P20A181A -> false
YNFLJC39E06C956L -> true
YNFLJC39E06C956E -> false

Scoring

This is , the shortest number of bytes wins

\$\endgroup\$
2
  • 2
    \$\begingroup\$ Suggest test case where last character is number or promise it never happen \$\endgroup\$
    – l4m2
    Commented Jan 22 at 10:45
  • 1
    \$\begingroup\$ @l4m2 It will never happen \$\endgroup\$ Commented Jan 22 at 10:53

9 Answers 9

3
\$\begingroup\$

Jelly, 33 31 bytes

ØWiⱮịÐo“ÐVẈ÷{⁷.ƝİRḟ’Œ?¤’N0¦S26ḍ

Try it online!

A monadic link taking a string and returning 1 for valid and 0 for invalid.

Explanation

ØWiⱮ                            | Index of each character in word characters (A-Aa-z0-9)
    ịÐo“ÐVẈ÷{⁷.ƝİRḟ’Œ?¤         | Index odd positions in the list into the 15593538177379092215583486‘th permutation of 1..26; leave even ones alone
                       ’        | Decrease by 1
                        N0¦     | Negate the final value
                           S    | Sum
                            26ḍ | Is divisible by 26
\$\endgroup\$
2
\$\begingroup\$

JavaScript (Node.js), 117 bytes

f=([a,...x],s=i=0)=>x+x?f(x,s+g(++i%2?'BAFHJNPRTVCESULDGIMOQKWZYX'[g(a)]:a)):g(a)==s%26
g=x=>1/x?+x:parseInt(x,36)-10

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Python 3, 165 159 bytes

lambda s:chr((sum(ord(x)-48-17*(x>':')for x in s[1:-1:2])+sum(b"! %')-/135! %')-/135\"$24+#&(,.0*6987"[ord(x)-48-7*(x>':')]-32for x in s[:-1:2]))%26+65)==s[-1]

Try it online!

-3 bytes thanks to @CommanderMaster's amazing observation about removing the constant v!

-3 bytes by using multiplication instead of indexing on the condition.


A function that accepts a parameter s, which is the code to be validated.

It returns

chr((S_E+S_O)%26+65)==s[-1]

That is, evaluates the remainder between the sum of both sets (S_O odd characters, S_E even characters) and 26, adds 65 to it (i.e. transforms a number 0-25 to A-Z using ASCII conversion) and checks if it's equal to the last character of the input.

S_E is

sum(ord(x)-48-17*(x>':')for x in s[1:-1:2])

x>':' is a condition that evaluates to true (or 1) if the character x is a letter (since its ASCII code is higher than :'s). Therefore, it'll subtract 48 from the ASCII code of x if its numeric, otherwise it'll subtract 65. It basically maps '0' -> 0, ... '9' -> 9, 'A' -> 0, ..., 'Z' -> 25 and sum the resulting values.

S_O is

sum(b"! %')-/135! %')-/135\"$24+#&(,.0*6987"[ord(x)-48-7*(x>':')]-32for x in s[:-1:2])

If you take every ASCII code of the bytestring characters and subtract 32, you will see that it'll match the odd-characters table. So that's a transformation similar to S_E's, but it now maps '0' -> 0, ... '9' -> 9, 'A' -> 10, ..., 'Z' -> 35, get the byte at that bytestring index and subtract 32.

\$\endgroup\$
4
  • \$\begingroup\$ I might be missing something, but removing v and just writing 48 twice is shorter by three bytes \$\endgroup\$ Commented Jan 22 at 16:36
  • \$\begingroup\$ @CommandMaster You haven't missed absolutely anything! That's correct, I've updated the solution \$\endgroup\$
    – enzo
    Commented Jan 22 at 16:43
  • \$\begingroup\$ ord(x)%65%48? \$\endgroup\$
    – l4m2
    Commented Jan 22 at 19:30
  • \$\begingroup\$ Also subtract 52(=2*26) rather than 32 and no need to explicitly subtract \$\endgroup\$
    – l4m2
    Commented Jan 22 at 19:33
1
\$\begingroup\$

APL+WIN, 161 bytes

Prompts for string.

c←8 2⍴⎕⋄c[7;1]=a[26|+/((('BAKPLCQDREVOSFTGUHMINJWZYX'⍳c[;0])~26),(¯65+⎕av⍳'BAFHJNPRTV')[(n⍳c[;0])~10]),(((n←(⍕⍳10)~' ')⍳c[;1])~10),((a←⎕av[65+⍳26])⍳¯1↓c[;1])~26]

Try it online! Thanksto Dyalog Classic

\$\endgroup\$
1
\$\begingroup\$

Perl 5 -pF, 137 bytes

$c=pop@F;pairmap{$s+=$b=~s|\D|-65+ord$&|er+($a=~/\d/?1+$a*2-($a==1)+2*($a>4):BAKPLCQDREVOSFTGUHMINJWZYX=~/$a/*"@-")}@F;$_=$s%26+65==ord$c

Try it online!

\$\endgroup\$
1
\$\begingroup\$

05AB1E, 36 32 bytes

25Ý•D+>∞¢-‹ ŸΔŒ•.IžKIkι`Šèì`(O₂Ö

-4 bytes by porting @NickKennedy's Jelly answer.

Input as a list of characters.

Try it online or verify all test cases.

Explanation:

25Ý              # Push a list in the range [0,25]
   •D+>∞¢-‹ ŸΔŒ• # Push compressed integer 15593538177379092215583485
     .I          # Get the (0-based) 15593538177379092215583485th permutation of the [0,25]-list:
                 #  [1,0,5,7,9,13,15,17,19,21,2,4,18,20,11,3,6,8,12,14,16,10,22,25,24,23]
žK               # Push constant "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
  Ik             # Get the (0-based) index of each character of the input in this string
    ι            # Uninterleave it into two parts
     `           # Pop and push both parts to the stack
      Š          # Triple-swap the three lists on the stack
       è         # Index the 0-based even indices into the permuted list
        ì        # Prepend-merge the two lists back together
         `       # Pop and push all integers separated to the stack
          (      # Negate the last one
           O     # Sum all integers on the stack together
            ₂Ö   # Check whether this sum is divisible by 26
                 # (after which it is output implicitly as result)

See this 05AB1E tip of mine (section How to compress large integers?) to understand why •D+>∞¢-‹ ŸΔŒ• is 15593538177379092215583485.
The 15593538177379092215583485 is generated using Jelly's \$n^{th}\$ permutation builtin œ¿: try it online (minus 1, because 05AB1E uses 0-based indexing and Jelly 1-based indexing).

\$\endgroup\$
2
  • 1
    \$\begingroup\$ I didn’t know 05AB1E had a permutation built-in like Jelly. Your Jelly comment TIO link is slightly off - Œ¿ is monadic so is just finding the permutation number for the sorted first argument. œ¿ is what you meant if you’re looking for the dyadic version, though here the result is identical because the second argument is the sorted version of the first one! \$\endgroup\$ Commented Jan 25 at 18:02
  • 1
    \$\begingroup\$ @NickKennedy Woops, I copied the wrong Jelly builtin. Fixed it. And yes, 05AB1E's .I is equivalent to Jelly's œ?, but unfortunately it only works on lists. \$\endgroup\$ Commented Jan 25 at 18:35
0
\$\begingroup\$

Excel ms365, 199 bytes

Assuming input in A1:

=CHAR(MOD(SUM(MAP(ROW(1:15),LAMBDA(i,TOROW(FIND(MID(A1,i,1),IF(ISODD(i),{"10   2 3 4   5 6 7 8 9","BAKPLCQDREVOSFTGUHMINJWZYX"},{"0123456789","ABCDEFGHIJKLMNOPQRSTUVWXYZ"})),3)-1))),26)+65)=RIGHT(A1)
\$\endgroup\$
0
\$\begingroup\$

Funge-98, 108 bytes

"NRTS"4(I'0>'v00p
<@.!-+A'g20w1p21-1:g21p20%'+g20+-fg3-+0'*'`9':\-+0'*'`9':

 "$!#%('&

Try it online!

Contains non-printable characters, so here is a hex dump:

00000000: 224e 5254 5322 3428 4927 303e 2776 3030  "NRTS"4(I'0>'v00
00000010: 700a 3c40 2e21 2d2b 4127 6732 3077 3170  p.<@.!-+A'g20w1p
00000020: 3231 2d31 3a67 3231 7032 3025 1a27 2b67  21-1:g21p20%.'+g
00000030: 3230 2b2d 6667 332d 2b30 272a 1127 6039  20+-fg3-+0'*.'`9
00000040: 273a 5c2d 2b30 272a 1127 6039 273a 0a00  ':\-+0'*.'`9':..
00000050: 080a 100f 1416 181c 1e20 2224 1113 2123  ......... "$..!#
00000060: 1a12 1517 1b1d 1f19 2528 2726            ........%('&
\$\endgroup\$
0
\$\begingroup\$

Charcoal, 50 bytes

FS⊞υ⌕⁺α⭆χκι¬﹪⁻⊟υΣEυ⎇﹪κ²ι⌕᧔$⌈⊟⌈σEζ⊖)"⁷hY✂&⊕⧴C”ι²⁶

Try it online! Link is to verbose version of code. Outputs a Charcoal boolean, i.e. - for a valid code, nothing if not. Explanation:

FS⊞υ⌕⁺α⭆χκι

Loop through the input string, converting each character into its index in the string A..Z0..9.

¬﹪⁻⊟υΣEυ⎇﹪κ²ι⌕᧔...”ι²⁶

Remove the last value, permute alternate elements (permutation string shamelessly stolen from @Arnauld's answer), take the sum, and compare the the removed last value modulo 26.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.