リーダーマクロを定義する:ダブルクォート型 - lisp-cookbook-ja/common-lisp GitHub Wiki
標準のリーダーマクロである「"」と同じタイプの例です。
(defun read-string (stream close-char)
(with-output-to-string (out)
(do ((char (read-char stream nil :eof) (read-char stream nil :eof)))
((or (eq char :eof) (char= char close-char))
(if (eq char :eof)
(error 'end-of-file :stream stream)))
(when (char= #\\ char)
(setq char (read-char stream nil :eof))
(if (eq char :eof)
(error 'end-of-file :stream stream)))
(princ char out))))
リーダーがマクロ文字に遭遇すると、指定した終端の文字までを読み込み文字列として返します。
上記では、終端文字を文字列に含めるには、\でエスケープすることにしています。
;;; %〜%を文字列として読む
(let ((*readtable* (copy-readtable nil)))
(set-macro-character #\% #'read-string)
(with-input-from-string (in "%foo bar \\%baz%") (read in)))
;=> "foo bar %baz"
;;; 「〜」を文字列として読む
(let ((*readtable* (copy-readtable nil)))
(set-macro-character #\「 (lambda (s c) (read-string s #\」)))
(with-input-from-string (in "「あいうえお かきくけこ「さしすせそ\\」」")
(read in)))
;=> "あいうえお かきくけこ「さしすせそ」"