代码之家  ›  专栏  ›  技术社区  ›  wutch

使用命名参数设置Lisp字符串格式

  •  12
  • wutch  · 技术社区  · 10 年前

    在Lisp中有没有一种方法可以使用命名参数格式化字符串?

    也许有关联列表

    (format t "All for ~(who)a and ~(who)a for all!~%" ((who . "one")))
    

    为了打印 "All for one and one for all" .

    类似 this python question this scala one ,甚至 c++ ,但在Lisp中。

    如果语言中没有这个功能,有没有人有任何很酷的函数或宏可以完成同样的事情?

    1 回复  |  直到 9 年前
        1
  •  18
  •   coredump    8 年前

    使用 CL-INTERPOL .

    (cl-interpol:enable-interpol-syntax)
    

    字符串插值

    对于简单的情况,您不需要 FORMAT :

    (lambda (who) #?"All for $(who) and $(who) for all!")
    

    然后:

    (funcall * "one")
    => "All for one and one for all!"
    

    解释格式指令

    如果需要格式化,可以执行以下操作:

    (setf cl-interpol:*interpolate-format-directives* t)
    

    例如,此表达式:

    (let ((who "one"))
      (princ #?"All for ~A(who) and ~S(who) for all!~%"))
    

    …打印:

    All for one and "one" for all!
    

    如果你好奇,上面的 读取 作为:

    (LET ((WHO "one"))
      (PRINC
        (WITH-OUTPUT-TO-STRING (#:G1177)
          (WRITE-STRING "All for " #:G1177)
          (FORMAT #:G1177 "~A" (PROGN WHO))
          (WRITE-STRING " and " #:G1177)
          (FORMAT #:G1177 "~S" (PROGN WHO))
          (WRITE-STRING " for all!" #:G1177))))
    

    备用读卡器功能

    以前,我全局设置 *interpolate-format-directives* ,它解释所有插值字符串中的格式指令。 如果您想精确控制插入格式指令的时间,那么您不能只是在代码中临时绑定变量,因为魔法发生在读取时。相反,您必须使用自定义读取器功能。

    (set-dispatch-macro-character
     #\#
     #\F
     (lambda (&rest args)
       (let ((cl-interpol:*interpolate-format-directives* t))
         (apply #'cl-interpol:interpol-reader args))))
    

    如果我将特殊变量重置为其默认值NIL,那么格式化指令的字符串将以 #F ,而正常插值使用 #? 语法。如果要更改可读表,请查看 named readtables .