การแทนที่สตริงชื่อ?


13

ฉันมักจะต้องทำการแทนที่ของสตริงเดียวกันหลายครั้ง:

(format "%s %s %s" "a" "a" "a") ;; gives: "a a a"

(เป็นเพียงตัวอย่างหลอกๆในกรณีนี้ดีกว่าที่จะใช้กาว "a" กับช่องว่าง แต่โดยทั่วไปแล้วฉันจัดการกับสถานการณ์ที่ซับซ้อนมากขึ้น)

มีวิธีที่จะทำการทดแทนที่มีชื่อหรือไม่? เช่นในไพ ธ อนคนหนึ่งจะเขียน:

"{0} {0} {0}".format("a") # or:
"{name} {name} {name}".format(name="a")


@Malabarba: ผมโพสต์ vestion แก้ไขคำตอบจากหัวข้อที่นี่เป็นคำตอบ
Adobe

คำตอบ:


16

การเขียนคำตอบนี้ใหม่จะช่วยแก้ปัญหาอื่น:

(format-spec "%a %a %a %b %b %b" (format-spec-make ?a "a" ?b "b"))

แก้ไข : format-specโซลูชันอื่น

ในฐานะที่เป็น Malabarba ให้ทางออกอื่นในการแสดงความคิดเห็น:

(format-spec "%a %a %a %b %b %b" '((?a . "a") (?b . "b")))

แก้ไข 2 : การประเมินผลก่อนการทดแทน:

นี่คือตัวอย่างของการประเมินผลก่อนการทดแทน:

(let ( (a 1)
       (b 2) )
  (message (format-spec "a = %a; b = %b" (format-spec-make ?a a ?b b))) )
;; ⇒ a = 1; b = 1

(let ( (a 1)
       (b 2) )
  (message (format-spec "a = %a; b = %b" `((?a . ,a) (?b . ,b)))) )
;; ⇒ a = 1; b = 2

3
โปรดทราบด้วยว่าformat-spec-makeเป็นเพียงผู้มีชื่อเสียง:'((?a . "a") (?b . "b"))
Malabarba

1
"ดูเหมือนว่าจะใช้ไม่ได้กับตัวเลข" - ดูemacs.stackexchange.com/questions/7481/…
npostavs

@npostavs: เยี่ยมมากที่จะรู้! ฉันแก้ไขคำตอบ
Adobe

14

Magnar Sveen ของสตริงการจัดการห้องสมุดs.elให้ความหลากหลายของวิธีการที่จะทำเช่นนี้ ตัวอย่างเช่น:

(require 's)
(s-format "${name} ${name} ${name}" 'aget '(("name" . "test")))
;; ==> "test test test"

โปรดทราบว่าs-formatสามารถใช้ฟังก์ชั่นทดแทนใด ๆ แต่ยังมีการจัดการพิเศษสำหรับaget, และelt gethashดังนั้นคุณสามารถใช้รายการโทเค็นและอ้างอิงโดยดัชนีเช่น:

(s-format "$0 $0 $0 $1 $1 $1" 'elt '("a" "b"))
;; ==> "a a a b b b"

คุณยังสามารถแทนที่โดยใช้ตัวแปรในขอบเขตเช่นนี้

(let ((name "test"))
  (s-lex-format "${name} ${name} ${name}"))
;; ==> "test test test"

1
ยอดเยี่ยมฉันไม่รู้เกี่ยวกับคุณลักษณะนี้! ฉันใช้ s.el เป็นส่วนใหญ่ในการดูวิธีการทำงานของการจัดการสตริงที่พบบ่อยใน Emacs แต่นี่เป็นมากกว่าเพียงแค่ wrapper บรรทัดเดียวของฟังก์ชันที่มีอยู่
wasamasa

3

รูปแบบ 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


3

ไม่ใช่วัตถุประสงค์ทั่วไป แต่จะแก้ปัญหากรณีของคุณ:

(apply 'format "%s %s %s" (make-list 3 'a))

ใช้ตัวอย่างที่มีให้:

(apply 'format (concat " * - :raw-html:`<img width=\"100%%\" "
                       "src=\"http://xxx.xxx/images/languages/"
                       "staff/%s.jpg\" alt=\"%s.jpg\"/>` - .. _%s:")
       (make-list 3 'some-image))

ให้:

" * - :raw-html:`<img width=\"100%\" src=\"http://xxx.xxx/images/languages/staff/some-image.jpg\" alt=\"some-image.jpg\"/>` - .. _some-image:"

นี่คือสตริงตัวอย่างที่ฉันจัดการ: " * - :raw-html:`<img width=\"100%%\" src=\"http://xxx.xxx/images/languages/staff/%s.jpg\" alt=\"%s.jpg\"/>` - .. _%s:"- ทั้งหมด%sเหมือนกัน
Adobe

@Adobe ฉันได้อัปเดตคำตอบพร้อมตัวอย่างของคุณแล้ว
wvxvw
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.