85 omemo.vim (9-1) 書籍JANコード解釈スクリプト(ファイルタイププラグイン作成中)

ファイルタイププラグインを書くことでVimスクリプトを勉強している。詳細はまたそのうち書くつもり。今書いているファイルタイププラグインはメモ用のもの。俺用のメモファイルタイプなので omemo としている。仮だけど。中身はといえば、howmそのまま。URLを開けて、ISBNから書籍情報を取得できて、容易に機能追加ができて、とそういうもの。

そのプラグインの中では、以前書いた howm-actionlock-isbn.vim に手を入れたものを使っている。そのまま流用してはつまらないので、手を入れている。変更点は、「書籍JANコードの2段目のバーコードも解釈できるようにした」ことだ。今回は、その断片を書く。

書籍JANコードの1段目はISBN-13、2段目はCコードと価格情報を表していることがわかった。書籍情報取得先に「ジュンク堂」を追加するスクリプトを書いているうちに、Cコードや価格情報の存在を知ったので、これを使わない手はないなと思った。それが、今回の改造のきっかけになった。

これだけだと動作確認しにくいと思うので、ジュンク堂うんぬんの分もそのうちに公開する。

function! s:get_jan2(c_code, price)
  let code = '192' . a:c_code . printf('%05d', a:price)
  return code . s:get_jan2_cdigit(code)
endfunction

function! s:get_jan2_info(code)
  if !s:is_jan2(a:code) | return {} | endif
  let matchlist = matchlist(a:code, '\(\d\{3}\)\(\d\{4}\)\(\d\{5}\)\d')
  let tax    = get(matchlist, 1, '')
  let c_code = get(matchlist, 2, '')
  let price  = get(matchlist, 3, '')
  let price = substitute(price, '^0*', '', '')
  if tax == '191'
    " 3% のときは内税。四捨五入もする。
    let price = price * 10
    let price = price * 100 / 103
    let price = (price + 5) / 10
    " let price = 'P' . price . 'E'
  elseif tax == '192'
    " 5% のときは外税。特別な処理は必要ない。
    " let price = '\' . price . 'E'
  endif
  let price3 = price * 10
  let price3 = price3 * 103 / 100
  let price3 = (price3 + 5) / 10
  let price5 = price * 10
  let price5 = price5 * 105 / 100
  let price5 = (price5 + 5) / 10
  return {'c-code': c_code, 'price': price, 'price3': price3, 'price5': price5}
endfunction

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:get_jan2_cdigit(code)
  return s:get_isbn13_cdigit(a:code)
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:is_jan2(s)
  return s:is_isbn13(a:s)
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

function! s:isbn13toasin(isbn13)
  let hatena_url = 'http://d.hatena.ne.jp/asin/' . a:isbn13
  let tmpfile = tempname()
  call system('curl -D ' . tmpfile . ' ' . hatena_url)
  let pat = '\clocation:\s*http://d.hatena.ne.jp/asin/\(\d\{9}[0-9x]\)'
  let loc = get(filter(readfile(tmpfile), "v:val =~ '" . pat . "'"), 0, '')
  call delete(tmpfile)
  return get(matchlist(loc, pat), 1, '')
endfunction