首页 文章

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

提问于
浏览
0

我有一个以 (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但它存储在一个文件中 . 我需要能够在关联列表中获取此数据以达到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 (打开“路径”))获取整个文件但是我想要的时候(关联'A1(读 s ))或(关联'KEY(读 s) *)它让我无处可去 . 你对如何实现这个有什么想法吗?

2 回答

  • 3

    @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)))
    
  • 1

    您可以使用内置函数 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)))
    

    文件内容看起来像一个条目集合,每个条目都是一个键值对列表 . 虽然您可以使用插槽名称 keybczfeats 等来定义名为 entry 的结构或类,然后使用诸如 (entry-bcz x) 之类的访问器而不是 (second (assoc 'bcz x)) ,但它中没有任何内容将其连接到CLOS . 这可能有助于提高可读性和效率,但要做到这一点,您需要从这个基于列表的数据表示中创建对象 .

相关问题