รูปแบบ s-lex ของ s.el นั้นเป็นสิ่งที่คุณต้องการจริงๆ แต่ถ้าคุณต้องการที่จะใส่โค้ดลงในบล็อคการทดแทนและไม่ใช่แค่ชื่อตัวแปรฉันเขียนสิ่งนี้เพื่อพิสูจน์แนวคิด
(defmacro fmt (str)
"Elisp string interpolation for any expression."
(let ((exprs nil))
(with-temp-buffer
(insert str)
(goto-char 1)
(while (re-search-forward "#{" nil t 1)
(let ((here (point))
(emptyp (eql (char-after) ?})))
(unless emptyp (push (read (buffer-substring (point) (progn (forward-sexp 1) (point)))) exprs))
(delete-region (- here 2) (progn (search-forward "}") (point)))
(unless emptyp (insert "%s"))
(ignore-errors (forward-char 1))))
(append (list 'format (buffer-string)) (reverse exprs)))))
;; demo with variable and code substitution
(fmt "My name is #{user-full-name}, I am running Emacs #{(if (display-graphic-p) \"with a GUI\" \"in a terminal\")}.")
;; results in
"My name is Jordon Biondo, I am running Emacs with a GUI."
คุณสามารถฝังfmt
สายไว้ในอีกสายfmt
ถ้าคุณบ้า
(fmt "#{(fmt\"#{(fmt\\\"#{user-full-name}\\\")}\")}")
;; =>
"Jordon Biondo"
รหัสเพิ่งขยายไปสู่การformat
โทรดังนั้นการแทนที่ทั้งหมดจะเสร็จสิ้นตามลำดับและประเมินผล ณ เวลารันไทม์
(cl-prettyexpand '(fmt "Hello, I'm running Emacs #{emacs-version} on a #{system-type} machine with #{(length (window-list))} open windows."))
;; expands to
(format "Hello, I'm running Emacs %s on a %s machine with %s open windows."
emacs-version
system-type
(length (window-list)))
การปรับปรุงสามารถทำได้กับประเภทรูปแบบที่ใช้แทนการใช้% s ทุกครั้ง แต่จะต้องทำที่รันไทม์และจะเพิ่มค่าใช้จ่าย แต่สามารถทำได้โดยการล้อมรอบทุกรูปแบบ args ในการเรียกใช้ฟังก์ชั่น ในรูปแบบ แต่จริงๆแล้วสถานการณ์เดียวที่คุณต้องการนั่นน่าจะเป็นแบบลอยตัวและคุณสามารถทำได้ (รูปแบบ "% f" โฟลต) ในการเปลี่ยนตัวคือคุณหมดหวัง
หากฉันทำงานมากกว่านี้ฉันมีแนวโน้มที่จะอัปเดตส่วนสำคัญนี้แทนคำตอบนี้ https://gist.github.com/jordonbiondo/c4e22b4289be130bc59b