strjis: 日本語テキスト入出力ライブラリ
【追記】ISO-2022-JP-2004に対応しました。
strjisの紹介
Common Lispで日本語のテキストを読み書きするライブラリを作成しました。
下記のエンコードを扱うことができます。
Common Lispにて日本語を読み書きする方法は、すでに色々と存在します。
わざわざこのライブラリを使用する必要はないかもしれません。
日本語を読み書きする一般的な方法は、 次の情報が参考になると思います。
LISPUSER Common Lisp と 日本語 と 文字コード
http://lispuser.net/commonlisp/japanese.html逆引きCommon Lisp 処理系:日本語の扱い
https://lisphub.jp/common-lisp/cookbook/index.cgi?p=%bd%e8%cd%fd%b7%cf%3a%c6%fc%cb%dc%b8%ec%a4%ce%b0%b7%a4%a4
本ライブラリは次の利点があります。
- 全部ANSI Common Lispで作成してある
- 各エンコード間で変換ができる
- 「JIS X 0213のコード対応表」を使っている
- JISエンコードの読み書きができる
欠点も色々とあります。
stream
として扱えない (stream
への入出力は可)open
の:external-format
に指定できない- 規格に厳密に従っているわけではない
今回は標準ANSI Common Lispだけで作りたかったので、 例えば配列から配列へ変換するような作りになっています。 別の機会にでも、勉強してstreamに対応させたりしてみたいです。
UNICODEの変換表は、下記のサイトを参考にさせていただきました。
Unicode Consortium
http://www.unicode.org/
http://www.unicode.org/Public/MAPPINGS/OBSOLETE/EASTASIA/JIS
http://www.unicode.org/Public/UNIDATA/EastAsianWidth.txtJIS X 0213のコード対応表
http://x0213.org/codetable/
http://x0213.org/codetable/iso-2022-jp-2004-std.txt
JIS X 0213のコード対応表につきましては、「Copyright (c) 2006-2017 Project X0213」さんが 作成したものであり、自由に使用・配布・改変等してもよいとのことでしたので、 加工して変換テーブルの実装に利用させていただきました。 ありがとうございます。
ライブラリの使用方法は下記のファイルにまとめました。
https://github.com/nptcl/strjis/blob/master/docs/readme.ja
動作確認はsbcl
, clisp
, ccl
にて行っています。
ただ、これらは全てbase-char
が21bit以上のコードを格納できる処理系です。
例えばAllegroCL
やLispWorks
なんかは、一文字16bitで処理しているとのことで、
そうなるとどこまでうまく動くかどうかわかりません。
使用例を下記に示します。
strjisの使い方
簡単な使い方をいくつか載せます。
JISをUTF-8に変換
JISの文字1B 24 42 あいう
を変換します。
(coerce-list '(#x1B #x24 #x42 #x24 #x22 #x24 #x24 #x24 #x26) :input 'jis :output 'utf8) -> (227 129 130 227 129 132 227 129 134)
SHIFT-JISからUTF-8 BOMありに変換
あいう
を変換します。
(coerce-list #(#x82 #xA0 #x82 #xA2 #x82 #xA4) :input 'shiftjis :output 'utf8bom) -> (239 187 191 227 129 130 227 129 132 227 129 134)
リストではなく配列を返却したい
関数coerce-vector
を使用します。
(coerce-vector '(#x82 #xA0 #x82 #xA2 #x82 #xA4) :input 'shiftjis :output 'utf8bom) -> #(239 187 191 227 129 130 227 129 132 227 129 134)
入力に文字列を指定したい
処理系がUnicode対応である必要があります。
(coerce-list "Hello" :output 'eucjis) -> (72 101 108 108 111)
出力を文字列にしたい
処理系がUnicode対応である必要があります。
(coerce-string '(#x1B #x24 #x42 #x24 #x22 #x24 #x24 #x24 #x26) :input 'jis) -> "あいう"
ファイルを変換したい
テキストファイルをJISに変換します。
処理系がUnicode対応である必要があります。
(with-open-file (input #p"input.txt" :direction :input) (with-open-file (output #p"output.txt" :direction :output :if-exists :supersede :if-does-not-exist :create :element-type '(unsigned-byte 8)) (coerce-stream input output :output 'jis)))
入力のファイル形式を指定して変換したい
EUC-JISのテキストファイルをUTF-16BE BOMなしに変換します。
入力も出力も(unsigned-byte 8)
でopen
してください。
(with-open-file (input #p"input.txt" :direction :input :element-type '(unsigned-byte 8)) (with-open-file (output #p"output.txt" :direction :output :if-exists :supersede :if-does-not-exist :create :element-type '(unsigned-byte 8)) (coerce-stream input output :input 'eucjis :output 'utf16be)))
入力にbabel
を使いたい
文字列あいう
の読み込みをbabel
に任せます。
(coerce-list (babel:string-to-octets "あいう" :encoding :utf-8) :input 'utf8 :output 'utf16le) -> (66 48 68 48 70 48)
入力にopen
のexternal-format
を使いたい
sbcl
の実行例です。
(with-open-file (input #p"input.txt" :direction :input :external-format :utf-8) (coerce-list input :output 'utf16le)) -> UTF-16LEのリスト
ISO-2022-JPを読み込みたい
【追記】ISO-2022-JP-2004に対応しました。
入力ISO-2022-JPからUTF-8に変換。
(coerce-string x :input 'iso2022jp :output 'utf8) →ISO-2022-JPからUTF-8に変換
書き込みは、ISO-2022-JP-2004に対応しています。
(coerce-string x :input 'utf8 :output 'iso2022jp) →UTF-8からISO-2022-JP-2004に変換
ISO-2022-JPの扱いについては別途説明します。
https://github.com/nptcl/strjis/blob/master/docs/readme.ja
関数の説明
変換に使用する関数は次の通り。
(defun coerce-list (x &key input output) ...) (defun coerce-vector (x &key input output) ...) (defun coerce-string (x &key input output) ...) (defun coerce-stream (x output-stream &key input output) ...)
x
は入力データです。
数値の配列、数値のリスト、文字列、streamのどれかを指定できます。
input
は入力エンコードタイプであり、下記のsymbol
から選択します。
utf8 ascii jis eucjp eucjis shiftjis unicode utf16 utf16v utf16be utf16le utf32 utf32v utf32be utf32le
output
は出力エンコードタイプであり、下記のsymbolから選択します。
ascii jis eucjp eucjis shiftjis unicode utf8 utf8bom utf8no utf16 utf16v utf16be utf16le utf16bebom utf16lebom utf32 utf32v utf32be utf32le utf32bebom utf32lebom
utf16v
は、0
から#xFFFF
までの数値を扱います。
utf32v
は、0
から#x10FFFF
までの数値を扱います。
ascii
は#x00
~#x7F
までの文字を限定で扱います。
utf8no
は、BOMを除去します。
utf16
とutf32
は、BOMからbig-endianかlittle-endianを判定します。
BOMが無かったらbig-endianであるとみなします。
unicode
は、char-code-limit
の値を見て、適切なタイプを判断します。
もしchar-code-limit
が255
以下ならutf8
です。
もしchar-code-limit
が65535
以下ならutf16v
です。
それ以外ならutf32v
です。
その他
eucjp
とeucjis
は同じです。
JISのエスケープシーケンスは、第1・第2水準漢字に相当するものが、 JIS C 6226-1978, JIS X 0208-1983, JIS X 0208-1990, JIS X 0213:2000 1面, JIS X 0213:2004 1面と様々ありますが、 全部同じものとして処理します。 JIS X 0213:2000 2面とJIS X 0212-1990補助漢字すら同じに扱います。
規約違反のUnicode文字は全てエラーです。
例えばコードが#x110000
を超えていたり、
Surrogate Code Pointを使ってみたり、
UTF-8で冗長な方法で表現していた場合は読み込みません。