78 howm-mode.vim (2-42) howm-actionlock-isbn.vim の公開

howm-mode.vim 狙えパッチ適用版で、はてなダイアリーの isbn/asin 記法に対応するための設定スクリプトhowm-actionlock-isbn.vim」を公開しました。

ダウンロード: http://khkh.o0o0.jp/vim/howm-actionlock-isbn.vim

概要

howm-mode.vim 狙えパッチ適用版で、はてなダイアリーの isbn/asin 記法が使用できます。厳密には asin には対応していないので、isbn 記法 ( detail ) のみが使用できます。 isbn10 や isbn13 から、書籍の情報を取得できます。

=
[2008-04-07 14:35]
isbn:4861970016:detail

という風に isbn 記法を入力し、カーソルを上に置いてエンターキーを叩くと

=
[2008-04-07 14:35]
isbn:9784861970014:detail
坊ちゃん
作者: 夏目漱石
出版社/メーカー: フロンティアニセン
発売日: 2004/09/01
メディア: ?
http://d.hatena.ne.jp/asin/4861970016

こんな感じで情報を取得できます。isbn 記法内のコードが isbn10 の場合は、自動で isbn13 に置き換えます。以前の sync-isbn.vim と同様のものと考えていただいて結構です。

必要環境

  • howm-mode.vim 狙えパッチ適用版であること
  • curl が使用可能であること

curl については、Chalice で検索すればわかると思います。Chalice が動作していればきっと動作します。

導入方法

ダウンロードした howm-actionlock-isbn.vim を、以下のように vimrc で source コマンドを使って読み込んでください。

" パスは適宜修正してください
so ~/.vim/howm/howm-actionlock-isbn.vim

注意事項

isbn10 から isbn13 への変換はきっちりとしていますが、情報取得や isbn13 から asin への変換は「はてな頼み」です。

スクリプト解説とか

isbn の処理において、きちんとした手順を踏んでいることが大きな特徴です。

以前公開した sync-isbn.vim では、ひどい処理をしていました。大きな問題が二つあります。

一つ目の問題は isbn10 と asin を区別していないことです。 isbn13 を isbn10 に変換するつもりで、はてなダイアリーを使用していました。これは実際は asin に変換されています。今回のものは、isbn10 についてはすべて isbn13 に変換し、isbn13 から asin に変換する(情報を取得する)ために、はてなダイアリーを使用しています。今回は、きっちりと isbn10 と asin を区別しています。

二つ目の問題は isbn の妥当性をきちんと検証していないことです。 isbn10 / isbn13 にはチェックディジットがあります。これらの計算をしていませんでした。ですから、形式さえ同じであれば、isbn として通ってしまっていました。今回のものは、isbn10 / isbn13 ともに、形式だけでなくチェックディジットの計算を行っています。

今回のものでは、上記の二点以外に改善された点があります。それが「isbn10 から isbn13 への変換」です。先にすこし書いたとおり、今回のものは isbn10 を isbn13 に変換してしまいます。その過程でも、妥当性の確認を行い、より正確に変換しています。

繰り返しますが、isbn の処理がきちんとした手順を踏んでいます。ですから、isbn に関するコードに関しては、今回のものだけに限らず「流用できる」と考えています。

だらだらと書きすぎてしまいました。では、以下に実際のコードから、該当部分を抜粋しておきます。

function! s:get_isbn10_cdigit(isbn)
  if a:isbn !~# '\d\{9}' | return 0 | endif
  let sum = 0
  for i in range(9)
    let n = substitute(a:isbn, '^\d\{' . i . '}\(\d\)\d*$', '\1', '')
    let sum = sum + n * (10 - i)
  endfor
  let cdigit = (11 - (sum % 11))
  if cdigit == 10
    let cdigit = 'X'
  elseif cdigit == 11
    let cdigit = '0'
  else
    let cdigit = string(cdigit)
  endif
  return cdigit
endfunction

function! s:get_isbn13_cdigit(isbn)
  if a:isbn !~# '\d\{12}' | return 0 | endif
  let sum = 0
  for i in range(12)
    let n = substitute(a:isbn, '^\d\{' . i . '}\(\d\)\d*$', '\1', '')
    let sum = sum + n * (i % 2 == 0 ? 1 : 3)
  endfor
  let cdigit = (10 - (sum % 10))
  let cdigit = string(cdigit == 10 ? 0 : cdigit)
  return cdigit
endfunction

function! s:is_isbn10(s)
  if a:s !~# '^\d\{9}[0-9xX]$' | return 0 | endif
  let isbn10 = substitute(a:s, '^\(\d\{9}\)\([0-9xX]\)$', '\1', '')
  let cdigit = substitute(a:s, '^\(\d\{9}\)\([0-9xX]\)$', '\2', '')
  return (cdigit =~? s:get_isbn10_cdigit(isbn10))
endfunction

function! s:is_isbn13(s)
  if a:s !~# '^\d\{13}$' | return 0 | endif
  let isbn13 = substitute(a:s, '^\(\d\{12}\)\(\d\)$', '\1', '')
  let cdigit = substitute(a:s, '^\(\d\{12}\)\(\d\)$', '\2', '')
  return (cdigit =~? s:get_isbn13_cdigit(isbn13))
endfunction

function! s:isbn10to13(isbn10)
  if !s:is_isbn10(a:isbn10) | return '' | endif
  let isbn10 = substitute(a:isbn10, '^\(\d\{9}\)\([0-9xX]\)$', '\1', '')
  let isbn13 = '978' . isbn10
  let cdigit = s:get_isbn13_cdigit(isbn13)
  let isbn13 = isbn13 . cdigit
  if !s:is_isbn13(isbn13) | return '' | endif
  return isbn13
endfunction

わーい、チェックディジット計算まちがえてた