[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: decode-coding-regin() with utf-8
In article <b4m3bi4knrk.fsf@xxxxxxx>, Katsumi Yamaoka <yamaoka@xxxxxxx> writes:
> テキストを何かの coding system でエンコードしたものを unibyte
> なバッファに挿入してからデコードするときに、2005年3月の時点の
> Emacs 22.0.50 では、次のような順序で行なうとうまくいかなかった
> ようです。
> ;; [1]
> (decode-coding-region (point-min) (point-max) 'CODING-SYSTEM)
> (set-buffer-multibyte t)
> そこで、これに該当するコードを使っている emacs-w3m では、以下
> のように順序を逆にしました。
> ;; [2]
> (set-buffer-multibyte t)
> (decode-coding-region (point-min) (point-max) 'CODING-SYSTEM)
今更こんなことを言って申し訳ないのですが、
set-buffer-multibyte は非常に危い関数です。何せバッファの中の
unibyte と multibyte をごっちゃにするんですから。もしテキスト
を何かの coding system でエンコードしたものをまたデコードした
ければ
(decode-coding-string (encode-coding-string STR CODING1) CODING2)
を使うのが安全です (Emacs 22 でも 23 でも).
> ところが、現在の Emacs 22.0.50 では [1] のやり方でも問題無いよう
> に見えます。加えて、最新の Emacs 23.0.0 では、[1] のやり方を使わ
> ないと正しくデコードできません。例えば [2] の場合、Emacs 23.0.0
> ではこんなふうになります:
> (let ((str (encode-coding-string
> (string (make-char 'chinese-gb2312 86 80)
> (make-char 'chinese-gb2312 57 122))
> 'gb2312))
> (default-enable-multibyte-characters nil)
> str1 str2)
> (with-temp-buffer
> (insert str)
> (setq str1 (buffer-string))
> (set-buffer-multibyte t)
> (setq str2 (buffer-string))
> (decode-coding-region (point-min) (point-max) 'gb2312)
> (list str1 str2 (buffer-string))))
> => ("\326\320\271\372"
> "\326■\372"
> #("\326■\301\272" 0 2 (charset chinese-gb2312)))
Emacs 23 で multibyte buffer 中の multibyte character を
decode-coding-region でどう扱おうかはまだ迷っているのですが、
基本的には decode-coding-region を multibyte-buffer(特に
unibyte-buffer を (set-buffer-multibyte t) したもの)で使うの
はお勧めできません。上記についても、どうしても既に unibyte
buffer にあるものを decode してかつその結果を multibyte
buffer にしたければ、
(let ((str (buffer-string)))
(erase-buffer)
(set-buffer-multibyte t)
(insert (decode-coding-string str CODING)))
のようなことをやるのが安全です。2度も余計に string を作るの
が無駄なように思えますが、空でないバッファでの
set-buffer-multibyte はそれなりに重い処理なのでどちらが速い
かは一概には言えません。
ちなみに Emacs 23 では
(let ((str (buffer-string)))
(erase-buffer)
(set-buffer-multibyte t)
(decode-coding-string str CODING (current-buffer)))
や、別のバッファを返してよいのなら
(let ((buf (generate-new-buffer "*work*")))
(decode-coding-region (point-min) (point-max) 'iso-8859-1 buf)
buf)
という技も使えます。
> それから、これに関連して、[2] のやり方では扱うデータによっては
> decode-coding-region の時点で Emacs 23.0.0 がクラッシュするとい
> う報告があります[3]。それを再現するコードを作ってみました。やり
> 方はともかく、こういう条件で Emacs がクラッシュしてはいけないの
> ですよね。
おっと、 testcase を有難うございます。今修正を commit しまし
た。
---
半田@AIST