拆分格式字符串(格式 t ...)

时间:2021-02-22 16:24:04

标签: common-lisp

有时我喜欢用 (format t ..) 输出一些文本。
为了防止源代码中出现冗长的不可读格式字符串,并使输出易于对齐,我使用了 (format t (concatenate 'string ....)

示例:

(format t (concatenate 'string 
                       "some output~%"
                       "  error-msg: ~a~%"
                       "  uiop-cwd: ~a~%"
                       "  uiop-file-exists: ~a~%")
        "error foo"
        (uiop:getcwd)
        (uiop:file-exists-p "hello_world.bmp"))

在 Common Lisp 中是否有更惯用的和编译时的方式来做同样的事情?

2 个答案:

答案 0 :(得分:6)

这是一个等效的格式字符串,它使用 Tilde newline 格式指令,它忽略以下换行符和空格(直到下一个可见字符)。为了像您一样用空格缩进,我在空格前写了强制换行符 selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":"[id="yui_3_18_1_1_1614002255126_189"]"}

~%

(注意,这是一个单独的字符串,因此在编译时不需要进行连接。)

答案 1 :(得分:3)

您可以通过以下方式做得很好:

(defun fmt (to control/s &rest args-to-format)
  (declare (dynamic-extent args-to-format)) ;?OK
  (apply #'format to (if (listp control/s)
                         (apply #'concatenate 'string control/s)
                       control/s)
         args-to-format))

(define-compiler-macro fmt (&whole form to control/s &rest args-to-format)
  (cond
   ((stringp control/s)
    `(format ,to ,control/s ,@args-to-format))
   ((and (listp control/s)
         (eql (first control/s) 'quote))
    ;; literal
    (destructuring-bind (_ thing) control/s
      (declare (ignore _))
      (print "here")
      (if (and (listp thing) (every #'stringp thing))
          `(format ,to ,(apply #'concatenate 'string thing) ,@args-to-format)
        form)))
   (t
    form)))

编译器宏应确保

的常见情况
(fmt t '("~&foo: ~S~%"
         "bar~%") ...)

完全没有运行时成本。