如何使用Lisp将数字列表转换为分隔字符串?

如何使用Lisp将数字列表转换为分隔字符串?,lisp,common-lisp,s-expression,Lisp,Common Lisp,S Expression,给定以下代码: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Copyright (C) 2014 Wojciech Siewierski ;; ;; ;; ;; This progra

给定以下代码:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Copyright (C) 2014  Wojciech Siewierski                               ;;
;;                                                                       ;;
;; This program is free software: you can redistribute it and/or modify  ;;
;; it under the terms of the GNU General Public License as published by  ;;
;; the Free Software Foundation, either version 3 of the License, or     ;;
;; (at your option) any later version.                                   ;;
;;                                                                       ;;
;; This program is distributed in the hope that it will be useful,       ;;
;; but WITHOUT ANY WARRANTY; without even the implied warranty of        ;;
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         ;;
;; GNU General Public License for more details.                          ;;
;;                                                                       ;;
;; You should have received a copy of the GNU General Public License     ;;
;; along with this program.  If not, see <http://www.gnu.org/licenses/>. ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


(defvar *output*)
(defvar *indent*)

(defun format-tag (symbol &optional arg)
  (cond
    ((equal arg 'begin)
     (format nil "~{~a~}<~(~a~)" *indent* symbol))
    ((equal arg 'end)
     (format nil "~{~a~}<~(/~a~)>~%" *indent* symbol))
    (t
     (format nil "~{~a~}~a~%" *indent* symbol))))

(defun sexp-to-xml--inside-tag (sexp)
  (if sexp
      (if (listp (car sexp))
          (progn
            (sexp-to-xml--new-tag (car sexp))
            (sexp-to-xml--inside-tag (cdr sexp)))
          (progn
            (push (format-tag
                   (string (car sexp)))
                  *output*)
            (sexp-to-xml--inside-tag (cdr sexp))))))

(defun sexp-to-xml--attrs (plist)
  (when plist
    (push (format nil " ~(~a~)=~s"
                  (car plist)
                  (cadr plist))
          *output*)
    (sexp-to-xml--attrs (cddr plist))))

(defun sexp-to-xml--new-tag (sexp)
  (if (listp (car sexp))
      (progn
        (push (format-tag (caar sexp) 'begin)
              *output*)
        (sexp-to-xml--attrs (cdar sexp)))
      (push (format-tag (car sexp) 'begin)
            *output*))
  (unless (cdr sexp)
    (push (format nil " /")
          *output*))
  (push (format nil ">~%")
        *output*)
  (let ((*indent* (cons "  " *indent*)))
    (sexp-to-xml--inside-tag (cdr sexp)))
  (when (cdr sexp)
    (push (format-tag (if (listp (car sexp))
                          (caar sexp)
                          (car sexp))
                      'end)
          *output*)))

(defun sexp-to-xml-unquoted (&rest sexps)
  (apply #'concatenate 'string
         (apply #'concatenate 'list
                         (loop for sexp in sexps collecting
                              (let ((*output* nil)
                                    (*indent* nil))
                                (reverse (sexp-to-xml--new-tag  sexp)))))))

(defmacro sexp-to-xml (&rest sexps)
  `(format *standard-output* "~a"
           (sexp-to-xml-unquoted ,@(loop for sexp in sexps collecting
                                        `(quote ,sexp)))))
(defun file-get-contents (filename)
  (with-open-file (stream filename)
    (let ((contents (make-string (file-length stream))))
      (read-sequence contents stream)
      contents)))

(defun file-get-lines (filename)
  (with-open-file (stream filename)
    (loop for line = (read-line stream nil)
          while line
          collect line)))

(defun list-to-string (lst)
    (format nil "~{~A~}" lst))


(defun test1()
  (let((input (file-get-contents "sample2.sexp")))
    (format t (sexp-to-xml-unquoted (read-from-string "(head (title \"my-site\"))")))
  )
)

(defun test2()
  (let((input (file-get-lines "sample2.sexp")))
    (loop for sexp in input do (print (write-to-string sexp)))
  )
)

(defun test3()
  (let((input (file-get-lines "sample2.sexp")))
    (format t (list-to-string input))
  )
)


(defun :str->lst (str / i lst)
  (repeat (setq i (strlen str))
    (setq lst (cons (substr str (1+ (setq i (1- i))) 1) lst)))) 

(defun print-elements-recursively (list)
 (when list                            ; do-again-test
       (print (car list))              ; body
       (print-elements-recursively     ; recursive call
        (cdr list))))                  ; next-step-expression


(defun tokenize( str )(read-from-string (concatenate 'string "(" str
")")))


(defun test4()
  (let((input (file-get-contents "sample2.sexp")))
    (print-elements-recursively (tokenize input) )
  )
)


(defun test5()
  (let((input (file-get-contents "sample2.sexp")))
    (print (sexp-to-xml-unquoted (tokenize input)))
  )
)

(defun test6()
  (let((input (file-get-contents "sample2.sexp")))
    (loop for sexp in  (tokenize input) do (
      with-input-from-string (s (write-to-string sexp) ) 
        (print ( sexp-to-xml-unquoted (read s)) )

      )
    )
  )
)


(defun test7()
  (let((input (file-get-contents "sample2.sexp")))
    (loop for sexp in  (tokenize input) do (
      print sexp

      )
    )
  )
)

(defun test8()
  (let((input (file-get-contents "sample2.sexp")))
    (format t (sexp-to-xml-unquoted (read-from-string input)))
  )
)

但使用test8会产生一个错误:

 7 is not a string designator.
这让我写了一个这样的文件:

(supertux瓷砖) (tilegroup (名称(“雪”)) (瓷砖 "7" ) ) )

然后它会很好地编译并生成xml,但我不知道如何将所有整数转换为它们的字符串表示形式,从列表中读取。我尝试解析字符串并使用write-to-string方法,但我认为我遗漏了一些东西

任何帮助都将受到感激

谢谢

--编辑--

将princ字符串更改为coredump建议的字符串可以修复字符串中原始数字的解析计算,但是,当尝试计算t等符号时,会发生以下情况:

没有为#\T定义分派函数

以以下内容为例

(tile
    ; dupe of tile 70, this one will be removed.
    (id 63)
    (deprecated #t)
    (images
      "tilesets/background/backgroundtile1.png"
    )

  )
不过,看起来,对Lisp之外的变量求值将只通过检查“t”xml标记来保持


这个问题解决了。

在谷歌上快速搜索,可以找到以下存储库();链接的代码足以重现错误。请注意,当我从Emacs/Slime内部运行它时,调试器会显示回溯:

  0: (STRING 7)
  1: (SEXP-TO-XML--INSIDE-TAG (7 8 9 202 13 14 ...))
  2: (SEXP-TO-XML--NEW-TAG (TILES 7 8 9 202 13 ...))
  3: (SEXP-TO-XML--INSIDE-TAG ((TILES 7 8 9 202 13 ...)))
  4: (SEXP-TO-XML--INSIDE-TAG ((NAME (_ "Snow")) (TILES 7 8 9 202 13 ...)))
  5: (SEXP-TO-XML--NEW-TAG (TILEGROUP (NAME (_ "Snow")) (TILES 7 8 9 202 13 ...)))
  6: (SEXP-TO-XML--INSIDE-TAG ((TILEGROUP (NAME #) (TILES 7 8 9 202 13 ...))))
  7: (SEXP-TO-XML--NEW-TAG (SUPERTUX-TILES (TILEGROUP (NAME #) (TILES 7 8 9 202 13 ...))))
  8: (SEXP-TO-XML-UNQUOTED (SUPERTUX-TILES (TILEGROUP (NAME #) (TILES 7 8 9 202 13 ...))))
在上面列出的各种堆栈帧上按v键,我可以在调用堆栈中找到代码当前暂停的位置

我没有加载lisp文件,只是在当前Emacs缓冲区中计算了不同的表单,因此没有与函数关联的源文件。但是,AST表单是为了调试而存储的,调试器可以精确定位当前代码执行的位置,并用一个伪
(#::***此处***…)
表单包装:

(SB-INT:NAMED-LAMBDA SEXP-TO-XML--INSIDE-TAG
    (SEXP)
  (BLOCK SEXP-TO-XML--INSIDE-TAG
    (IF SEXP
        (IF (LISTP (CAR SEXP))
            (PROGN
             (SEXP-TO-XML--NEW-TAG (CAR SEXP))
             (SEXP-TO-XML--INSIDE-TAG (CDR SEXP)))
            (PROGN
             (PUSH (FORMAT-TAG (#:***HERE*** (STRING (CAR SEXP)))) *OUTPUT*)
             (SEXP-TO-XML--INSIDE-TAG (CDR SEXP)))))))

对任意值调用
string
将不起作用,您需要在
sexp to xml--inside标记中用
princ to string
替换它。然后它就如预期的那样工作了。

在谷歌上快速搜索,可以找到以下存储库();链接的代码足以重现错误。请注意,当我从Emacs/Slime内部运行它时,调试器会显示回溯:

  0: (STRING 7)
  1: (SEXP-TO-XML--INSIDE-TAG (7 8 9 202 13 14 ...))
  2: (SEXP-TO-XML--NEW-TAG (TILES 7 8 9 202 13 ...))
  3: (SEXP-TO-XML--INSIDE-TAG ((TILES 7 8 9 202 13 ...)))
  4: (SEXP-TO-XML--INSIDE-TAG ((NAME (_ "Snow")) (TILES 7 8 9 202 13 ...)))
  5: (SEXP-TO-XML--NEW-TAG (TILEGROUP (NAME (_ "Snow")) (TILES 7 8 9 202 13 ...)))
  6: (SEXP-TO-XML--INSIDE-TAG ((TILEGROUP (NAME #) (TILES 7 8 9 202 13 ...))))
  7: (SEXP-TO-XML--NEW-TAG (SUPERTUX-TILES (TILEGROUP (NAME #) (TILES 7 8 9 202 13 ...))))
  8: (SEXP-TO-XML-UNQUOTED (SUPERTUX-TILES (TILEGROUP (NAME #) (TILES 7 8 9 202 13 ...))))
在上面列出的各种堆栈帧上按v键,我可以在调用堆栈中找到代码当前暂停的位置

我没有加载lisp文件,只是在当前Emacs缓冲区中计算了不同的表单,因此没有与函数关联的源文件。但是,AST表单是为了调试而存储的,调试器可以精确定位当前代码执行的位置,并用一个伪
(#::***此处***…)
表单包装:

(SB-INT:NAMED-LAMBDA SEXP-TO-XML--INSIDE-TAG
    (SEXP)
  (BLOCK SEXP-TO-XML--INSIDE-TAG
    (IF SEXP
        (IF (LISTP (CAR SEXP))
            (PROGN
             (SEXP-TO-XML--NEW-TAG (CAR SEXP))
             (SEXP-TO-XML--INSIDE-TAG (CDR SEXP)))
            (PROGN
             (PUSH (FORMAT-TAG (#:***HERE*** (STRING (CAR SEXP)))) *OUTPUT*)
             (SEXP-TO-XML--INSIDE-TAG (CDR SEXP)))))))

对任意值调用
string
将不起作用,您需要在
sexp to xml--inside标记中用
princ to string
替换它。这完全解决了这个问题,但是,当使用t符号解析sexps时,它抛出以下命令:
没有为#\t定义分派函数
#t不是标准的公共Lisp语法,它看起来像Scheme。在您的上下文中,只需编写T就可以解决问题。如果您必须解析现有代码,您可能需要添加一个reader函数。是的,因为我相信它的计算结果是一个可能是布尔值或其他值的现有变量,但只需编写T就可以了。我相信,我们只需要检查属性是否有值,这样读取T就足够了。谢谢这完全解决了问题,但是,当使用t符号解析sexps时,它抛出以下命令:
没有为#\t
#定义分派函数,t不是标准的公共Lisp语法,它看起来像Scheme。在您的上下文中,只需编写T就可以解决问题。如果您必须解析现有代码,您可能需要添加一个reader函数。是的,因为我相信它的计算结果是一个可能是布尔值或其他值的现有变量,但只需编写T就可以了。我相信,我们只需要检查属性是否有值,这样读取T就足够了。谢谢