从文件流到常见Lisp中的assoc-list

时间:2018-12-09 14:25:50

标签: common-lisp file-read clos

我有一个以 (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)开头的文件...........继续这样。

我猜这是一个CLOS,但是它存储在文件中。我需要能够以assoc列表的形式获取此数据以到达A1或A2等作为密钥,以在事后获取其值。我现在要做的是逐行读取文件并对其执行字符串操作。但是我认为这确实是一个坏习惯。这是我现在的代码;

(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

我知道我可以使用(defparameter * s *(打开“路径”))来获取整个文件,但是我想做的时间是(assoc'A1(read * s *))或(assoc'KEY(读* s *))它使我无处可去。您对如何实现这一目标有任何想法吗?

2 个答案:

答案 0 :(得分:3)

您可以使用内置函数load来读取文件:

(load "/tmp/data.lisp")

这将设置变量*myfile*,因此您可以执行以下操作:

* (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

如果您不信任文件内容,并且想要读取文件中的源代码,但不想执行load会执行) ),则可以使用read。在那种情况下,还可以将*read-eval*绑定到nil上,以防止使用#.,否则将在读取时执行代码:

(with-open-file (f "/tmp/data.lisp")
  (let ((*read-eval* nil))
    (loop for form = (read f nil nil)
          while form
          do (print form)))

文件内容看起来像一个条目的集合,每个条目都有一个键值对列表。尽管您可以使用插槽名称entrykeybcz等定义一个名为feats的结构或类,然后再使用像(entry-bcz x)而不是(second (assoc 'bcz x))这样的访问器。这可能有助于提高可读性和效率,但是要做到这一点,您需要从此基于列表的数据表示形式创建对象。

答案 1 :(得分:1)

@zut很好地展示了如何在不评估内容的情况下读取文件。

我正在使用它,并向您展示如何从第一个表达式中获取键值对。

;; read-in-first-expression from file
(defparameter *f* (with-open-file (f "~/Dropbox/cl/test-file.lisp")
            (let ((*read-eval* nil))
              (loop for form = (read f nil nil)
                        while form
                collect form))))
*f*
;; first expression (defparameter expression):
(defparameter *f-1st-expr* (first *f*))
*f-1st-expr*

;; ;; I was trying to get to the data part of the first expression trying/using:
;; (first (second (third *f-1st-expr*)))
;; (second (second (third *f-1st-expr*)))

;; let's say these are lists of small lists of length 2

(defun two-element-lists-to-alist (two-list)
  (mapcar (lambda (p) (cons (first p)
                (let ((el (cdr p)))
                  (if (and (atom (car el)) (= (length el) 1))
                  (car el)
                  el))))
      two-list))

(defun convert-to-alists (read-in-defparameter-expression)
  (let ((data (second (third read-in-defparameter-expression))))
    (mapcar #'two-element-lists-to-alist data)))

;; convert to list of alists
(defparameter *alists* (convert-to-alists *f-1st-expr*))

;; ;; one can now access within the list of a lists using assoc and elt
;; ;; the key-value pairs
;; (assoc 'KEY (elt *alists* 0))
;; (assoc 'KEY (elt *alists* 1))
;; (assoc 'A1  (elt *alists* 0))

;; write a function to directly access key-value-pair of nth alist in alists
(defun get-key-from-nth (alists key nth)
  (assoc key (elt alists nth)))

;; testing:
(get-key-from-nth *alists* 'A1 0) ;; (A1 . CAN)
(get-key-from-nth *alists* 'A1 1) ;; (A1 . KEDIYI)
(get-key-from-nth *alists* 'KEY 0) ;; (KEY . 1)
(get-key-from-nth *alists* 'KEY 1) ;; (KEY . 2)
;; works!

~/Dropbox/cl/test-file.lisp的内容是:

    (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-so-on)))