LISP文件I/O-提取并转换信息



我有一个基本上像这样的文件(furniture.lisp)(还有更多条目):

(addgv :furniture 'stove
  (make-instance 'stove
    :pose (tf:make-pose-stamped
            "map"                         ; frame-id
            0.0
            (tf:make-3d-vector -3.1 -0.9 0)     ; translation/origin
            (tf:euler->quaternion :az 0))))
(addgv :furniture 'drawers-cupboard
  (make-instance 'cupboard
    :pose (tf:make-pose-stamped
            "map"
            0.0
            (tf:make-3d-vector -3.1 0.1 0)
            (tf:euler->quaternion :az 0))))

现在,我想拥有一个函数 (get-locations "furniture.lisp" "locations.txt"),该函数将对象坐标提取在3D-vector中,并将其输出写入文件:

(location stove -3.1 -0.9 9)
(location drawers-cupboard -3.1 0.1 0)
...

我首先写一个表达式,该表达式在文件中读取(到目前为止没有参数化)按行:

(ql:quickload "split-sequence")
(with-open-file (stream "furniture.lisp")
(do ((line (read-line stream nil)
           (read-line stream nil)))
    ((null line))
    (princ (split-sequence::split-sequence #Space line)) ; Just for demonstration
 ))

,但我意识到我没有机会/想法"连接"对象的名称(例如炉灶)及其坐标。我需要在"(addgv"的名称和变量"单词距离"之后的第二个符号。

(defun make-list-from-text (fn)
  (with-open-file (stream fn)
    (loop for line = (read-line stream nil nil)
          while line
          collect
               (split-sequence::split-sequence #Space line))))

每行都是一个冠军(我不知道这个子结构是否是一个优势,也许我应该"弄平"结果)。现在我被困了。此外,我有一种感觉,我的方法不知所措。

编辑:

我遵循了Svante的方法,最后获得了所需的输出!除了创建虚拟软件包外,我还必须为软件包创建虚拟导出(例如:export :make-3d-vector)。此外,:key #'car不起作用,因为我的列表是一个"混合"列表,由标准列表(例如(make-instance ...))和符号(例如addgv)组成。因此,我创建了一个辅助功能:

(defun find-helper (list-or-symbol)
    (if (listp list-or-symbol)
       (car list-or-symbol)
        list-or-symbol))

并由#'find-helper替换#'car

我的想法是创建一个虚拟tf软件包,然后read表格并分析您需要的任何内容。这样的东西(未经测试):

(eval-when (:compile-toplevel :load-toplevel :execute)
  (unless (find-package #:tf)
    (defpackage #:tf)))
(defun extract-location-file ()
  (let ((*read-eval* nil))
    (with-open-file (in "furniture.lisp")
      (with-open-file (out "locations.txt"
                           :direction :output
                           :if-exists :supersede
                           :if-does-not-exist :create)
        (loop :for form := (read in nil)
              :while form
              :do (print (extract-location form) out)
                  (terpri)))))
(defun extract-location (form)
  `(location ,(third form)
             ,@(rest (find 'tf::make-3d-vector
                           (find 'tf::make-pose-stamped
                                 (find 'make-instance
                                       form
                                       :key #'car)
                                 :key #'car)
                           :key #'car))))

请确保不要省略将*read-eval*绑定到nil

一般方法是:

  1. 将整个文件读为字符串(请参阅此处)
  2. (cl-ppcre:regex-replace-all "tf::?" content ""),即更换所有引用到软件包tf以避免与软件包相关的错误
  3. '()放在内容周围
  4. read it并分配到变量
  5. 现在您已经有了可以使用各种列表操纵功能来处理的结构化数据

不幸的是,这将是一个不可携带的解决方案:

  • 处理读者错误
  • 做解决问题所需的事情
  • 继续

例如,在lispworks中,我可以做这样的事情(只是草图):

CL-USER 60 > (defun test ()
               (handler-bind ((conditions:package-not-found-reader
                               (lambda (c)
                                 (continue c)))
                              (conditions:simple-reader-error
                               (lambda (c)
                                 (continue c))))
                     (read-from-string "'(foo27:bar19 bar18:foo44)")))
TEST
CL-USER 61 > (test)
(QUOTE (FOO27::BAR19 BAR18::FOO44))

它调用继续重新启动丢失的软件包错误,然后将符号未导出的错误。重新启动创建软件包,另一个正在返回一个非出口符号...

最新更新