55 sync.vim (4-3) sync-isbn.vim の精度向上と文字コードとマッチングと

http://d.hatena.ne.jp/eclipse-a/20080221/1203578419

以前書いた sync-isbn.vim を更新した。

きっかけ

sync-isbn.vim を使って、『狐罠』の情報を取得しようとしたら、なにやら表示がおかしかった。なぜか「ISBN:〜」とか取得してた。それはもうがっかりがっくりがっくしだった。

原因

前回、正規表現を使って「作者:〜」みたいな欄を取得しようとしたが、うまくマッチしなくて、仕方なくul.list-circleの子要素のうちn番目のli要素を作者とする、てないい加減なプログラムを作ったから。

修正

前回、うまくマッチしなかった理由を調べた。僕の予想が間違いでなければ、文字コードが原因。

:h charset-conversion
:h multibyte

:scriptencoding utf-8 という状態で、はてなからひっぱってきた HTML を iconv() で euc-jp から utf-8 に変換した。それで得られた文字列とスクリプト中に記述された日本語のマッチングは失敗する。さて、どうしてでしょう?

それが、さきに書いた charset-conversion の部分。:scriptencoding と 'encoding' が違う場合の自動変換のせいだと思う。実際に、iconv() での変換を &encoding として、特になにも考えず日本語でマッチングしたら成功した。

'encoding' は cp932 で、:scriptencoding は utf-8 、ちなみに 'fileencoding' は utf-8 。保存されたファイルは書き込み時に utf-8 で保存されるが、Vim上での扱いは 'encoding' の値である cp932 。utf-8 で保存されているからといって、読み込まれてしまえば cp932 になる。なので、iconv() で変換する先の文字コードutf-8 ではなく、&encoding の値である cp932 にしなければならない。 iconv() で utf-8 に変換した場合、cp932 と utf-8 の比較になり失敗する。

とそんな解釈でいいんじゃないだろうか。ごめん、実はあんまり検証してない。

結論

iconv() の変換先文字コードは &encoding にしておけばいい。深く考える必要はない。わざわざ、文字コードを数値に直したり、特定の文字コードに変換しようとする必要はない。

とりあえず

sync-isbn.vim を更新したよ!グローバル変数でフォーマットを設定できるようにしてみたよ!やったね!

おまけ

se enc=utf-8
e ++fenc=utf-8

で、utf-8 ぽく動くんだと思う。

おまけ2

function! F1()
  let c = matchstr(getline('.'), '.', col('.') - 1)
  let c = iconv(c, &enc, 'utf-8')
  let save_enc = &enc
  set encoding=utf8
  let c = printf("%04X", char2nr(c))
  let &enc = save_enc
  execute 'normal a' . c
endfunction

char2nr() で、指定した文字の文字コードがわかるんだけど、この文字コードはそのときの 'encoding' に依存する。'statusline' の %B も文字コードを調べられるんだけど、これも 'encoding' に依存する。正規表現の \u を使いたい、文字コードがほしい、という場合に、なかなか面倒になる。そこで、さきの関数のように iconv() で変換後の文字列を取得した上で、いったん 'encoding' を変更して char2nr() とする、欲しい文字コードが得られたら、忘れず 'encoding' を戻して終了。注意としては、これっぽいのを 'statusline' にいれるとすっごいちらつくこと。

一応ね

一応、スクリプトのURL書いておくね。

http://kuhun.s1.zmx.jp/Vim/sync-isbn.vim