I have a file that starts with
(defparameter *myfile*
'(((KEY 1) (A1 CAN) (A2 4)
(SUR (((BCZ S) (FEATS NIL)) (DIR FS) (LADOM ALL)
(((NNEW S) (FEATS NIL)) (DIR BS) (LADOM ALL)
((NNEW NP) (FEATS ((BIG NOM)))))))
(SEM (LAM P (P "CAN"))) (PARAM 1.0))
((KEY 2) (A1 KEDIYI) (A2 4)
...........and goes on like this.
I am guessing this is a CLOS but it is stored in a file. I need to be able to get this data in an assoc-list to reach the A1 or A2 etc. as keys to obtain their values afterwards. What I do now is reading the file line by line and do string operations on it. But I think it is really a bad practice. Here is my code for now;
(defun open_ded (path)
(defvar last_id 0)
(let ((in (open path :if-does-not-exist nil)))
(when in
(loop for line = (read-line in nil)
while line
do
(if (setq key_id (findkeyid line)) ;search "KEY" and return its id value
(setq last_id key_id)) ;if it is not nil, set it to last_id
And I know that I can get the whole file with (defparameter *s* (open "path")) but the when I want to do (assoc 'A1 (read *s*)) or (assoc 'KEY (read *s*)) it gets me nowhere. Do you have any ideas about how to achieve this?
You can use the built-in function load
to read the file:
(load "/tmp/data.lisp")
This will set variable *myfile*
so you can then do:
* (print *myfile*)
(((KEY 1) (A1 CAN) (A2 4)
(SUR
(((BCZ S) (FEATS NIL)) (DIR FS) (LADOM ALL)
(((NNEW S) (FEATS NIL)) (DIR BS) (LADOM ALL)
((NNEW NP) (FEATS ((BIG NOM)))))))
(SEM (LAM P (P "CAN"))) (PARAM 1.0))
((KEY 2) (A1 KEDIYI) (A2 4)))
(((KEY 1) (A1 CAN) (A2 4)
(SUR
(((BCZ S) (FEATS NIL)) (DIR FS) (LADOM ALL)
(((NNEW S) (FEATS NIL)) (DIR BS) (LADOM ALL)
((NNEW NP) (FEATS ((BIG NOM)))))))
(SEM (LAM P (P "CAN"))) (PARAM 1.0))
((KEY 2) (A1 KEDIYI) (A2 4)))
* (loop for i from 0
for entry in *myfile*
do (format t "Entry #~D: ~S~%" i entry))
Entry #0: ((KEY 1) (A1 CAN) (A2 4)
(SUR
(((BCZ S) (FEATS NIL)) (DIR FS) (LADOM ALL)
(((NNEW S) (FEATS NIL)) (DIR BS) (LADOM ALL)
((NNEW NP) (FEATS ((BIG NOM)))))))
(SEM (LAM P (P "CAN"))) (PARAM 1.0))
Entry #1: ((KEY 2) (A1 KEDIYI) (A2 4))
NIL
* (dolist (entry *myfile*)
(print (assoc 'key entry)))
(KEY 1)
(KEY 2)
NIL
If you don't trust the file contents, and you want to read the source code in the file but not execute it (which load
does), you would use read
. In that case also bind *read-eval*
to nil
to safeguard against uses of #.
that would otherwise execute code while being read:
(with-open-file (f "/tmp/data.lisp")
(let ((*read-eval* nil))
(loop for form = (read f nil nil)
while form
do (print form)))
The file contents looks like a collection of entries, with each entry a list of key-value pairs. There is nothing in it that connects it to CLOS, although you could define a structure or class named entry
with slot names key
, bcz
, feats
et cetera and then use accessors like (entry-bcz x)
instead of (second (assoc 'bcz x))
. This might help readability and efficiency, but to do that you need to create objects from this list-based data representation.