質問: Common lisp で 文字コードがわからない場合に推定してファイルを開きたいのです。 みなさんは文字コードのわからないファイルをどのようにして開いているのでしょうか? 私は fileをunsigned-byte 8のvectorにしてから、guessというライブラリを使おうとしています。文字コードは推定してくれますが、改行文字は推定してくれません。 guessは libguess を common lispにポーティングしたもので、で公開されています。
回答: 文字コードがわからない場合の処理としては、自分も (vector (unsigned-byte 8)) にしてから変換することが多いです。 ここまでは、定石かなと思いますが、ここから先の処理でCommon Lispに定番というものは、現状、無いのではないでしょうか。 文字コードがわからないということで、判定する必要があるわけですが、自分の場合、以前は、質問文でも出てきている guess の元になった onjo さん作の guess を利用したりしていました。 * 逆引きCommon Lisp: 外部からの入力バイト列を文字列にしたい(文字コード変換含む) しかし、ウェブなどは最近ほぼ UTF-8のページになったため、判定しないで無理矢理 ``` (or (ignore-errors (babel:octets-to-string os :encoding :utf-8)) (ignore-errors (babel:octets-to-string os :encoding :eucjp)) (ignore-errors (babel:octets-to-string os :encoding :cp932))) ``` 位で済ませてしまうことも多いです。 libguessは日本語以外にも対応しているとのことですので、かなり使い勝手は良いのではないでしょうか。 ちなみに、ABCLはJavaのライブラリが使えますが、JavaのICUをABCLから利用してみたこともあります。 (Clojureでは割とICUが使われたりすることがあるようです。) ICUにはJava版以外にもC版がありますが、こちらは試したことはありません。 改行コードについて Common Lispの#\Newlineは、環境によってLFだったりCR+LFだったり様々です。 エンコードを変換した後、処理することが多いのではないかと思います。 壊れた文字列について 関連して壊れた文字列も問題になりますが、RubyのString#scrub のようなものはCommon Lispには存在しないので、自作することになると思います。 自分は、SBCLの場合ですが、 ``` (defun scrub (octets) (handler-bind ((sb-impl::octet-decoding-error (lambda (c) (use-value "〓" c)))) (sb-ext:octets-to-string octets))) (defvar *broken* (coerce '(227 129 130 227 129 132 227 129 134 227 129 136 227 129) '(vector (unsigned-byte 8)))) (scrub *broken*) ;=> "あいうえ〓" ``` のようなものを作成して使用しています。