Ответ 1
Используйте 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!~%"))
... prints:
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))))
Если я reset специальная переменная имеет значение по умолчанию NIL, то строки, в которых форматируются директивы, имеют префикс #F
, тогда как обычные интерполированные используют синтаксис #?
. Если вы хотите изменить readtables, посмотрите named readtables.