LoginSignup
0
0

More than 5 years have passed since last update.

Scheme (R7RS+SRFI) でマイナンバーのチェックデジットを計算する

Last updated at Posted at 2015-11-18

流行っているようで Gauche 版も登場していたので、よりポータブルに R7RS で書きました。 SRFI-1 と SRFI-13 もサポートしている処理系でないと動かないので、Gauche と Sagittarius くらいしかなくて結局それほどポータブルというわけでもなかったりするのですが。

mynumber.scm

(import (scheme base)
        (scheme write)
        (scheme char)
        (srfi 1)
        (srfi 13))

(define (mynumber-assert p)
  (unless (string? p)
    (error "string required, but" p))
  (unless (= (string-length p) 12)
    (error "string of length 12 required, but" p))
  (unless (string-every digit-value p)
    (error "every elements of string must be digit, but" p)))  

(define (mynumber-checkdigit p)
  (let ((d (- 11
              (modulo (fold (lambda(pn qn a) (+ a (* pn qn)))
                            0
                            (map digit-value (string->list p))
                            '(6 5 4 3 2 7 6 5 4 3 2))
                      11))))
    (if (< 9 d) 0 d)))

(define (mynumber-validate? p)
  (mynumber-assert p)
  (= (digit-value (string-ref p 11))
     (mynumber-checkdigit p)))

;; test case
(for-each (lambda (x)
            (display x)
            (display " : ")
            (display (mynumber-validate? x))
            (newline))
          '("123456789010"
            "123456789011"
            "123456789012"
            "123456789013"
            "123456789014"
            "123456789015"
            "123456789016"
            "123456789017"
            "123456789018"
            "123456789019"
            "023456789013"))

入力が文字列ではなく数値で与えられる場合も考えてみました。 こちらは R7RS の範囲内だけで書いたのでより多くの処理系でそのまま使えます。 Gauche, Sagittarius, Larceny, Chibi, Foment で動作することを確認できています。

mynumber.scm
(import (scheme base)
        (scheme write))

(define (mynumber-validate? p)
  (unless (integer? p) (error "integer required" p))
  (let ((check-digit (modulo p 10)))
    (do ((r (quotient p 10) (quotient r 10))
         (c 0 (+ c (* (modulo r 10) (vector-ref '#(2 3 4 5 6 7 2 3 4 5 6) i))))
         (i 0 (+ i 1)))
        ((= i 11)
         (unless (= r 0) (error "number is too large" p))
         (let ((d (- 11 (modulo c 11))))
           (= (if (< 9 d) 0 d) check-digit))))))

;; test case
(for-each (lambda (x)
            (display x)
            (display " : ")
            (display (mynumber-validate? x))
            (newline))
          '(123456789010
            123456789011
            123456789012
            123456789013
            123456789014
            123456789015
            123456789016
            123456789017
            123456789018
            123456789019
            23456789013))
0
0
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
0
0