バイト列→文字列変換ライブラリ(sbcl)
前回の知見(文字コード変換関数をC++で用意する云々)を反映して、FFIを利用した、バイト列を文字列に変換するsbclのライブラリを作成した。
・unsafe-conv(0.0.1)
対応している文字コードは、UTF-8、Shift_JIS、EUC-JPの三つ。UTF-8以外のC++の変換関数については、この記事の末尾を参照(UTF-8に関しては前回を参照)。
完成度はともかく、速度だけならsbclの対応する関数(sb-ext:octets-to-string)より一桁程度速い。
;; 使える関数は一つだけ > (unsafe-conv:octets-to-string (sb-ext:string-to-octets "ライブラリ")) --> "ライブラリ" > (unsafe-conv:octets-to-string (sb-ext:string-to-octets "ライブラリ" :external-format :euc-jp) :external-format :euc-jp) --> "ライブラリ"
名前の通りあまり安全ではないので、一応注意点のようなものを(上記リンク先ファイルの)READMEに書いておきました。
もし使おうとする人がいたら、一読しておくようお願いします。
バイト列→ユニコード変換C++関数生成関数
バイト列から文字列に変換するC++の関数は、以下の関数群を用いて生成した。
;; バイト列とユニコードの対応テーブルを作成 (defun generate-convert-table (external-format) (loop FOR i FROM 0 BELOW char-code-limit FOR os = (ignore-errors (string-to-octets (string (code-char i)) :external-format external-format)) WHEN os COLLECT (list (coerce os 'list) i))) ;;; 以下二つの関数は、trie作成関連 (defun set-trie-value (trie key val) (if (null key) (setf (gethash :value trie) val) (set-trie-value (setf (gethash (car key) trie) (gethash (car key) trie (make-hash-table))) (cdr key) val))) (defun make-trie (convert-table) (let ((trie (make-hash-table))) (loop FOR (octets char-code) IN convert-table DO (set-trie-value trie octets char-code)) trie)) ;;; 以下二つはcppコード出力関連 (defun print-switch-statement (out trie level) (if (gethash :value trie) (format out " return ~D;~%" (gethash :value trie)) (progn (format out "~&~V@Tswitch(*s++){~%" (* level 4)) (maphash (lambda (code subtrie) (format out "~&~V@Tcase ~D:" (* level 4) code) (print-switch-statement out subtrie (1+ level)) (unless (gethash :value subtrie) (format out "~&~V@Tbreak;~%" (* (1+ level) 4)))) trie) (format out "~&~V@T}~%" (* level 4))))) (defun print-convert-c++-function (out external-format) (let ((trie (make-trie (generate-convert-table external-format)))) (format out "~&unsigned ~(~A~)_to_ucs(const unsigned char*& s) {~%" external-format) (print-switch-statement out trie 1) (format out "~&}~%"))) ;;;; 使用例 (with-open-file (out "sjis_to_ucs.h" :direction :output) (print-convert-c++-function out :sjis))