Adlandırılmış dize değiştirme?


13

Sık sık aynı dize birkaç yerine koymak zorunda:

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

(bu sadece kukla bir örnek, bu durumda bir boşlukla "a" yapıştırmak daha iyidir, ancak genel olarak daha karmaşık durumlarla ilgilenirim)

Adlandırılmış bir oyuncu değişikliği yapmanın bir yolu var mı? Örneğin python'da şöyle yazar:

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


@Malabarba: Ben bir şekilde burada bu iş parçacığı bazı cevabın değiştirilmiş vestion yayınlanmıştır cevap .
Adobe

Yanıtlar:


16

Bu cevabı yeniden yazmak başka bir çözüm sağlar:

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

Edit : Başka bir format-specçözüm

Malabarba yorumlarda başka bir çözüm sunduğundan:

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

Düzenleme 2 : Yerine koymadan önce değerlendirme:

İkame işleminden önce değerlendirilen örnekler:

(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
Ayrıca bunun format-spec-makesadece bir yazar olduğuna dikkat edin :'((?a . "a") (?b . "b"))
Malabarba

1
"sayılar için çalışmıyor gibi görünüyor" - bkz. emacs.stackexchange.com/questions/7481/…
npostavs

@ npostavs: Bilmek harika! Cevabı düzenledim.
Adobe

14

Magnar Sveen'in string manipülasyon kütüphanesi s.el bunu yapmak için çeşitli yollar sunar. Örneğin:

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

Not s-formatherhangi ikame fonksiyonunu alır, ama için özel işlem sağlar olabilir aget, eltve gethash. Böylece bir jeton listesi kullanabilir ve bunlara dizine göre başvurabilirsiniz, şöyle:

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

Kapsam içi değişkenleri kullanarak aşağıdakileri de değiştirebilirsiniz:

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

1
Mükemmel, bu özelliği bilmiyordum! Çoğu zaman sadece Emacs'ta ortak dize manipülasyon görevlerinin nasıl yapılacağına bakmak için s.el'i kullandım, ancak bu gerçekten mevcut bir işlevin tek satırlık bir paketleyicisinden daha fazlası.
wasamasa

3

s.el'in s-lex-formatı gerçekten istediğiniz şeydir, ancak kodu sadece değişken isimlere değil, ikame bloklarının içine koymak istiyorsanız, bunu bir kavram kanıtı olarak yazdım.

(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."

Hatta bir gömebilirsiniz fmtdiğerinin içine çağrıyı fmtDeli misin,

(fmt "#{(fmt\"#{(fmt\\\"#{user-full-name}\\\")}\")}")
;; =>
"Jordon Biondo"

Kod sadece bir formatçağrıya genişler, böylece tüm ikameler sırayla yapılır ve çalışma zamanında değerlendirilir.

(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)))

Her zaman% s kullanmak yerine hangi biçim türünün kullanıldığına ilişkin iyileştirmeler yapılabilir, ancak çalışma zamanında yapılması gerekir ve ek yük eklenir, ancak işleri güzel bir şekilde biçimlendiren bir işlev çağrısında tüm biçim bağımsız değişkenlerini çevreleyerek yapılabilir tipte ama gerçekten isteyebileceğiniz tek senaryo muhtemelen yüzüyor ve hatta (format "% f" float) bile yapabiliyordunuz.

Daha çok çalıştığımda, bu cevap yerine bu özeti güncelleme olasılığı daha yüksek. https://gist.github.com/jordonbiondo/c4e22b4289be130bc59b


3

Genel amaçlı değil, ancak vakanızı çözecek:

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

Sağlanan örneği kullanarak:

(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))

verir:

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

İşte ele aldığım örnek bir dize: " * - :raw-html:`<img width=\"100%%\" src=\"http://xxx.xxx/images/languages/staff/%s.jpg\" alt=\"%s.jpg\"/>` - .. _%s:"- hepsi %saynı.
Adobe

@Adobe Cevabı örneğinizle güncelledim.
wvxvw
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.