elispでisbn13->ASIN記法

http://d.hatena.ne.jp/tomisima/20071223/1198339760
おもしろそうなのでやってみました><
追記:

  • isbn-10にはBugがあります。
  • isbn13-to-isbn10もxxx-xxxxxxxxx-yではなくxxx-xxxxxxxxxyのときにはうまく計算できていません。

(コメント欄でplusさんが教えてくれました)
コメント欄のコードが正規表現のところや",'などが全角になってしまっているため記事の中にコードを追加。

;;plusさんのコード(こちらの方が良いです><)

(defun my-isbn13-to-isbn10 (isbn)
  (interactive "sEnter ISBN-13: ")
  (let ((isbn (replace-regexp-in-string "[- ]" "" isbn))
	(i 9)
	(check 0))
    (cond
     ((string-match "\\`[0-9]\\{13\\}\\'" isbn)
      (setq isbn (substring isbn 3 12))
      (while (> i 0)
	(setq check (+ check (* (- (aref isbn (- 9 i)) ?0) (1+ i))))
	(setq i (1- i)))
      (setq check (- 11 (% check 11)))
      (insert isbn (cond
		    ((= check 10)
		     "X")
		    ((= check 11)
		     "0")
		    (t
		     (number-to-string check)))))
     (t
      (message "Not ISBN-13")))))

以下は前に書いたもの。(bugがあります><)

(require 'cl)

(defun string-to-numlist (numbers)
  (mapcar (lambda (str) (string-to-number str))
	  (filter (lambda (elem) (not (or (equal elem "") (equal elem "-"))))
		  (split-string numbers ""))))

(defun fold (fn init lst)
  (do* ((result init (funcall fn result (car lst)))
	(lst lst (cdr lst)))
      ((null lst) result)))

(defun filter (p xs)
  (cond ((null xs) nil)
	((funcall p (car xs))
	 (cons (car xs) (filter p (cdr xs))))
	(t (filter p (cdr xs)))))


(defun isbn-10 (isbn)  ;;チェックデジットを調べる
  (let ((total
	 (fold (lambda (aa bb) (+ aa bb))
	       0
	       (mapcar* (lambda (x y) (* x y))
			(string-to-numlist isbn)
			'(10 9 8 7 6 5 4 3 2 1)))))
    (- 11 (% total 11))))

(defun isbn-13 (isbn)  ;;チェックデジットを調べる
  (let* ((total
	  (fold (lambda (aa bb) (+ aa bb))
		0
		(mapcar* (lambda (x y) (* x y))
			 (string-to-numlist isbn)
			 '(1 3 1 3 1 3 1 3 1 3 1 3))))
	 (n (% total 10)))
    (if (= n 0) 0 (- 10 n))))

;; 対話的に呼べない方
;; (defun isbn-13-to-10 (isbn)
;;   (let ((string9 (cadr (split-string 
;; 			(car (split-string isbn "-.$"))
;; 			"^.*?-"))))
;;     (concat (fold (lambda (x rest) (concat  x rest)) "" 
;; 		  (split-string string9 "-"))
;; 	    (number-to-string (isbn-10 string9)))))

;; (print (isbn-13-to-10 "978-4-8401-1984-9") (current-buffer))
;; "4840119848"

(defun isbn-13-to-10 (isbn) (interactive "s")
  (let ((string9 (cadr (split-string 
			(car (split-string isbn "-.$"))
			"^.*?-"))))
    (print (concat (fold (lambda (x rest) (concat  x rest)) "" 
			 (split-string string9 "-"))
		   (number-to-string (isbn-10 string9)))
    (current-buffer))))
(provide 'calc-isbn)

.emacs

(add-load-path "(上のコードを保存したディレクトリのパス)
(require 'calc-isbn)

とすると
M-x isbn-13-to-10で呼ぶことができます。ミニバッファにisbn-13を渡してあげるとASSIN形式でバッファに書き込まれます。