LoginSignup
2
2

More than 5 years have passed since last update.

OCaml でマイナンバーのチェックデジットを計算する

Posted at

cf. マイナンバーのチェックデジットを計算する
n+1 匹目のドジョウに挑戦。

mynumber.ml
let digits_pattern = Str.regexp "^[0-9]+$"

let checkdigit n =
  let q i =
    if i < 6 then i + 2
    else i - 4 in
  let rec accumulate n i acc =
    if n = 0 then 11 - (acc mod 11)
    else accumulate (n / 10) (i + 1) (acc + (n mod 10) * (q i)) in
  if String.length n <> 11
     || not (Str.string_match digits_pattern n 0) then None
  else Some (accumulate (int_of_string n) 0 0)

let valid n =
  String.length n = 12
  && Str.string_match digits_pattern n 0
  && let c = (int_of_char n.[11]) - (int_of_char '0') in
     let m = String.init 11 (fun i -> n.[i]) in
     match checkdigit m with
     | None -> false
     | Some d -> c = d

let () =
  List.iter
    (fun n -> Printf.printf "%s: %b\n" n @@ valid n)
    [ "123456789010";
      "123456789011";
      "123456789012";
      "123456789013";
      "123456789014";
      "123456789015";
      "123456789016";
      "123456789017";
      "123456789018";
      "123456789019";
      "023456789013" ]

checkdigit はマイナンバーの先頭11桁を string として取ってチェックディジットを計算する関数。入力文字列が数字じゃなかったり桁が足りない場合失敗するため戻り値の型は int option
valid はマイナンバー12桁を string で受けて checkdigit で得たチェックディジットが与えられたものと同じか突き合わせるだけ。

入力チェックは横着して正規表現。Str がサポートする正規表現は PCRE じゃないので \d[0-9] としています。\A\z もないので入力が改行を含む場合は知らない。

整数型が11桁以上必要なので 32bit 環境だと動かないと思います。

コンパイルして実行:

$ ocamlfind ocamlc -linkpkg -package str mynumber.ml
$ ./a.out 
123456789010: false
123456789011: false
123456789012: false
123456789013: false
123456789014: false
123456789015: false
123456789016: false
123456789017: false
123456789018: true
123456789019: false
023456789013: true

合ってますね。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2