--- title: isbn13→isbn10を求めるlispスクリプト author: kazu634 date: 2008-11-08 wordtwit_post_info: - 'O:8:"stdClass":13:{s:6:"manual";b:0;s:11:"tweet_times";i:1;s:5:"delay";i:0;s:7:"enabled";i:1;s:10:"separation";s:2:"60";s:7:"version";s:3:"3.7";s:14:"tweet_template";b:0;s:6:"status";i:2;s:6:"result";a:0:{}s:13:"tweet_counter";i:2;s:13:"tweet_log_ids";a:1:{i:0;i:4367;}s:9:"hash_tags";a:0:{}s:8:"accounts";a:1:{i:0;s:7:"kazu634";}}' categories: - gauche - Lisp ---

これで完結編だよ。

ソース

;; 引数が13桁の数字かどうかを判断する。
;; 13桁の場合はisbn10を求める
(define (isbn arg)
;; もし13桁の数字であれば
(if (rxmatch #/\d\d\d\d\d\d\d\d\d\d\d\d\d/ (number->string arg))
(begin
;; split-listの返り値のリストを表示する。
;; そのリストから最後の1桁を求め、最後に表示する。
(for-each (lambda (x) (display x)) (split-list (number->list arg)))
(display (chkdigit arg)))
;; 13桁の数字でなければ
(print "Not match")))
;; 数字からリストにする。後ろにShiroさんの別解あり
(define (number->list number)
(define (loop lis)
(cond [(null? lis) '()]
[else (cons (digit->integer (car lis)) (loop (cdr lis)))]))
(let ((num_list (string->list (number->string number))))
(loop num_list)))
;; isbn13から必要な部分だけを抜き出してリストにする。
;; これで10桁のうち9桁の数字が決まる。
(define (split-list list)
(drop-right (take-right list 10) 1))
;; チェックディジットを求める関数。残りの1桁がこれで判明する。
(define (chkdigit num)
(define (proc list)
(cond [(null? list) ]
[else (+ (* (car list) (+ 1 (length list))) (proc (cdr list)))]))
(let ((result (- 11 (modulo (proc (split-list (number->list num))) 11))))
(if (= result 10)
'X
result)))
;; number->list別解 - (1)
(define (number->list n)
(map digit->integer
(string->list (number->string n))))
;; number->list別解 - (2)
(define (number->list n)
(let loop ((n n) (r '()))
(if (< n 10)
(cons n r)
(loop (quotient n 10) (cons (modulo n 10) r)))))

これだけだとなにをやっているかわからないと思うので、Perl版が「2008-07-02 – 武蔵の日記」にあります。アルゴリズムはそっちをごらんください。

実行結果

プログラミングGauche』で試してみます。isbn13は9784873113487なので

gosh> (isbn 9784873113487)
4873113482#<undef>

という結果でした。確かめてみましょう。

20081108214239

asinはisbn10のことなので、asin記法のところを見ます。あってますね。というわけで、できました。