2
$\begingroup$

In Chile the RUT (Rol Único Tributario) is a national identification number. Every RUT has a check digit modulo 11. The RUT has 7 or 8 digits plus a check digit or letter.

I made this code that works for 7 digit RUTs, but not with 8-digit ones. A 7-digit number has the form abcdef-(check digit) and an 8-digit one is in the form abcdefg-(check digit).

How do I work with 8 digits?

Here are some valid RUT numbers to test the checker function: 9007920-4, 21620312-7, 13621690-2, 9329827-6, 5946647-k, 7425273-7, 17694763-2, 23212441-5, 21485432-5, 15459172-9, 10218932-9, 11316657-6, 24130358-6, 11377848-2, 18609823-4, 18004377-2, 8784472-2, 12357399-4, 12391279-9, 8304218-4.

(* Checker rut*)
rut = Input["Enter your rut without check digit"];
n = IntegerDigits[rut];
d1 = n[[7]];
d2 = n[[6]];
d3 = n[[5]];
d4 = n[[4]];
d5 = n[[3]];
d6 = n[[2]];
d7 = n[[1]];

s = d1*2 + d2*3 + d3*4 + d4*5 + d5*6 + d6*7 + d7*2 (*+d8*3 (8 digits)  *)
ri = Mod[s, 11];
rf = 11 - ri;

If[rf == 11, Print["The check digit is 0"]]
If[rf == 10, Print["The check digit is k"]]
If[rf < 10, Print["The check digit is ", rf]]
$\endgroup$
4
$\begingroup$
check[rut_] := 
 Module[{d = 11 - Mod[Total[IntegerDigits[rut]*{3, 2, 7, 6, 5, 4, 3, 2}], 11]},
  Which[d == 11, 0, d == 10, "K", True, d]]

Takes rut as integer (all digits less check digit), returns check code. Does not validate length of input, so add that if needed.

Update: Since you've added check examples, and since they contain both 7 and 8 body codes, it appears what you want is something that handles both, not just 8 as your title implies. Here's one way:

check[rut_Integer] := 
 Module[{d = 11 - Mod[Total[PadLeft[IntegerDigits[rut], 8]*{3, 2, 7, 6, 5, 4, 3, 2}], 
      11]}, Which[d == "11", 0, d == 10, "k", True, ToString@d]];

check[rut_String] :=
 Module[{chk = StringTake[rut, -1], bod = StringDrop[rut, -2]},
  If[StringLength@rut < 9, check[ToExpression@rut], 
   check[ToExpression[bod]] == chk]]

Note I've changed this to return the check code as a string (as your code does). You can call check with an integer or string representing the body of the code, and the check code will be returned, or call with the whole code as a string and true/false for validity will be returned.

Using your test examples:

tests = {"9007920-4", "21620312-7", "13621690-2", "9329827-6", 
  "5946647-k", "7425273-7", "17694763-2", "23212441-5", "21485432-5", 
  "15459172-9", "10218932-9", "11316657-6", "24130358-6", 
  "11377848-2", "18609823-4", "18004377-2", "8784472-2", "12357399-4",
   "12391279-9", "8304218-4"};

(* Check validity of whole RUT *)
check /@ tests

(* get check code for bodies, as strings, check against tests *)
(check /@ (StringDrop[#, -2] & /@ tests)) == (StringTake[#, -1] & /@tests)

(* get check code for bodies, as integers, check against tests *)
(check /@ (ToExpression@StringDrop[#, -2] & /@ tests)) == (StringTake[#, -1] & /@ tests)

(*
{True, True, True, True, True, True, True, True, True, True, True, \
True, True, True, True, True, True, True, True, True}

True

True

*)
$\endgroup$
  • $\begingroup$ @Works thank you explain the code to understand it better, Fdo $\endgroup$ – Fernando Silva Mar 21 '15 at 13:03
  • $\begingroup$ Any reason you use Total[Times[__]] instead of Dot[__]? Edge cases I'm not aware of? $\endgroup$ – 2012rcampion Mar 21 '15 at 19:22
  • 2
    $\begingroup$ @2012rcampion: No, just thought (based on OP code clip) that making it easy to read inside-out might be easier for OP to grok... $\endgroup$ – ciao Mar 21 '15 at 21:08
3
$\begingroup$

You seem to be referring to the Rol Único Tributario.

This article gives a verification algorithm. rasher already wrote the algorithm to compute the check digit, so I'll write something slightly different, the verification algorithm.

  1. Strip out all non-numeric characters, except an optional trailing K.
  2. Pad the number to nine digits with zeros on the left.
  3. Multiply each of the digits against a list of weights, treating K as 10, and total the results.
  4. Find the remainder modulo 11. If it is zero, the number is valid.

Here's the code:

verifyRUT[rut_String] := 
 Catch[Mod[
    PadLeft[If[Length[#] > 9, Throw[False], #] &@
       StringCases[
        StringTrim[rut], {d : DigitCharacter :> FromDigits[d], 
         "K" | "k" ~~ Except[DigitCharacter, _] ... ~~ EndOfString -> 
          10}], 9].{3, 2, 7, 6, 5, 4, 3, 2, 1}, 11] == 0]

Like rasher's function this doesn't test that the input length is not more than nine. If the length is greater than nine, returns False.

This works for all the examples you provided (and returns False for the random examples I came up with; still, you may want to include some known malformed RUTs in your test set).

This should also work for RUTs of any length up to nine (including checksum).

$\endgroup$
  • $\begingroup$ @Waiting upgrade, thanks $\endgroup$ – Fernando Silva Mar 21 '15 at 15:31
  • $\begingroup$ @For some reason your code does not work for me, nothing appears $\endgroup$ – Fernando Silva Mar 21 '15 at 22:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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