アプリ版:「スタンプのみでお礼する」機能のリリースについて

txtファイルからデータを読み込み、dataに付置したいです。
(setq data (with-open-file (in "/test.dat" :direction :input)))
って可能でしょうか?

また、テキストデータの中のデータの書式はどのようにすればいいですか?(テキストエディット使用)
データが文章なのですが、
("hi how are you" "hi how are you")こんな感じで大丈夫ですか?

A 回答 (1件)

うーん、こう言うのは質問投げるより自分で実際動かして確かめてみた方が良いんですけどね。



CL-USER> (with-open-file (out "~/test.dat" :direction :output)
      (let ((str "hi how are you"))
       (format out "~A~%~A~%" str str)))
NIL
CL-USER>

さて、作成されたtest.datファイルを開いてみます。

hi how are you
hi how are you

中身はこうなってなかったでしょうか?普通のテキストファイルに書かれたようになってますね。
つまり、2番目の質問に対しての答えは「どーでも良い」です(笑)。
実際、データをテキストとして保存する場合、書式は「あなたが決めるもの」です。これはCommon Lispに限らず、どんな言語でも同じで、つまりそれは「目的によって」パーズしやすいデータ形式を「あなたが」決めれば良い、って事ですね。
今回の場合はformat関数で「整形出力しろ」ってんでこーゆーカタチになったわけですが、もちろんリストにして保存してもO.K.です。全ては貴方が決める事です。色々試してみてください。
(ただ、一般に言って、リストの形式にしておけばreadで読み込みやすい、と言う特典はアリ)

ところで。
with-open-fileの書式は次のようになっています。

(with-open-file (変数 ファイル名 オプション) 本体)

ここで「変数」ですが、これはinだろうとoutだろうとsでもmでも大丈夫です。文字は何でも良いんですが、要するに、ファイルを開いたストリームの情報はここに束縛されるんですが、問題はこれは局所変数扱いでwith-open-fileの外側からは見えません。
上のコードでもそうですが、ストリーム情報を束縛したoutはwith-open-fileの「本体内」(上のコードではformat関数の第一引数)からは参照出来ますが、外側からは参照出来ないのです。
ちょっと実験してみましょうか。

CL-USER> (defparameter data nil)
DATA
CL-USER> (setf data (with-open-file (in "~/test.dat" :direction :input)))
;Compiler warnings :
; In an anonymous lambda form: Unused lexical variable IN

多分こんなカンジで、エラーを返してくるか、あるいは無限ループに突入すると思います。
何故なら、with-open-fileと言うマクロは、「ファイルを開いて」それから最後に「ファイルを閉じて」くれるわけですが、マクロ内で特に何かしろ、って本体で処理を書き込まない以上、ファイルを開けっ放しで「待ち」の状態に入ります。そうしてCommon Lisp処理系は(処理系からのエラー通達が無い限り)待機状態で止まってしまうのです。
つまり、やるなら、ストリーム情報を保持したいなら、最低でも次のように書くべきです。

CL-USER> (defparameter data nil)
DATA
CL-USER> (with-open-file (in "~/test.dat" :direction :input)
     (setf data in))
#<BASIC-FILE-CHARACTER-INPUT-STREAM ("C:/Users/cametan/test.dat"/:closed #x2100C932AD>
CL-USER>

これなら大域変数dataにinに束縛されたデータを束縛する事が出来ます。変数dataを見てみますか。

CL-USER> data
#<BASIC-FILE-CHARACTER-INPUT-STREAM ("C:/Users/cametan/test.dat"/:closed #x2100C932AD>
CL-USER>

何か分からんけどデータが束縛されてる模様です。
ところが、

CL-USER> (read-line data)
; Evaluation aborted on #<SIMPLE-ERROR #x2100B67C2D>.
CL-USER> (read data)
; Evaluation aborted on #<SIMPLE-ERROR #x2100B1051D>.
CL-USER> (read-char data)
; Evaluation aborted on #<SIMPLE-ERROR #x2100B63A3D>.
CL-USER>

何のデータが記述されてるのか読み出そうにもエラーを返してきますね。
これはこう言う事です。
with-open-fileと言うマクロはストリーム情報を返してきますが、with-open-file本体内に記述した作業を終えるとストリームを閉じるわけです。dataに束縛したストリームは既に閉じた情報なんで、これから何か読み出そうと言うのはあまり現実的ではありません。
つまり、やるなら「ストリームを閉じる前に」人間が認識出来るカタチでデータを読みだしてdataに束縛しなければならない、って事です。
要するに、質問者さんが恐らくやりたいのは次のようなコードでしょう。

CL-USER> (defparameter data nil)
DATA
CL-USER> (with-open-file (in "~/test.dat" :direction :input)
      (setf data
         (loop for line = (read-line in nil :eof)
           until (eq line :eof)
           collect line)))
("hi how are you" "hi how are you")

こう言う事じゃないですかね。大域変数dataの中身を見てみます。

CL-USER> data
("hi how are you" "hi how are you")
CL-USER>

キチンと「僕らに分かる形式で」束縛されてるのが分かりますね。

要するにまとめると

1. 「どんなカタチでファイルにデータをテキスト形式で保存するか」はデータ設計者に委ねられる。
2. Common Lispでもどんなテキスト形式でもデータが保存出来る(でも得手不得手から言うとリストが得意ではある)。
3. 故にパーズしやすい設計を自分で考えて決めてしまう。どんなカタチでもCommon Lispは一応対応出来る。
4. with-open-fileはファイルを開いてそのストリーム情報を第一引数内の第一引数(ややこしい・苦笑)に束縛するが、これはローカル変数扱いなので、with-open-fileの本体からしか参照出来ない。
5. ストリームから「目に見えて分かりやすい」データに変形するにはread、read-line、read-char等を使ってみる。

ですね。
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!