sbcl+aserveで日本語が通らない
最近はCommonLispでいろんな問題につっかかってるわけですが・・・
sbcl+aserveで、*html-output*に日本語を含んだ文字列を投げると、エラーになってしまう。
たとえば、
(publish :path "/" ... (let ((*standard-output* net.html.generator:*html-stream*)) (princ "あああ")))...
みたいにして、アクセスすると
4-aserve-worker: 01/12/09 - 20:39:09 - while processing command "GET / HTTP/1.1" got error The value 12354 is not of type (UNSIGNED-BYTE 8).
みたいになる。
sbclの日本語は内部のバイト列が符号無し8ビット値ではないらしい。
> (char-code #\あ) 12354
調べてみたところ、おそらく同じ事例として
http://unkar.jp/read/pc11.2ch.net/tech/1201402366#l249
http://unkar.jp/read/pc11.2ch.net/tech/1201402366#l534
のような情報がみつかったが、解決には至っていないようだ。
実行はCMUCLでやるべしとかかいてあるが、とてもじゃないがやりたくない。
で、途方にくれてたわけだが、色々な本を調べたりして結局解決した。
結局以下のようにした。
(defun to-octets-string (str) (let* ((arr (sb-ext:string-to-octets str :external-format sb-impl::*default-external-format* :null-terminate nil)) (len (length arr)) (ret (make-array len :fill-pointer 0 :element-type 'character))) (dotimes (i len) (vector-push (code-char (elt arr i)) ret)) ret)) (publish :path "/" ... (let ((*standard-output* net.html.generator:*html-stream*)) (princ (to-octets-string "あああ"))))...
to-octets-stringだが、まず、sb-ext:string-to-octetsで文字列を符号無し8ビット数列に変換し、
新しく作った文字としてパースされるベクタに再格納したものを返している。
こうするとto-octets-stringで変換後の文字列の日本語部分はslimeで化けてしまうが、
htmlではうまく表示された。