名前付き文字列の置換?


13

私はしばしば同じ文字列のいくつかの置換を行わなければなりません:

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

(これは単なるダミーの例です。この場合、「a」を空白で接着する方が良いですが、一般的にはより複雑な状況に対処します)

名前付き置換を行う方法はありますか?たとえば、Pythonでは次のように記述します。

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


@Malabarba:私は、ここでそのスレッドからいくつかの回答の修正vestionを掲載答え
アドビ

回答:


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"))
リストで

1
「数字のために動作していないようです」 -を参照emacs.stackexchange.com/questions/7481/...を
npostavs

@npostavs:知っておくといい!答えを編集しました。
アドビ

14

Magnar Sveenの文字列操作ライブラリs.elは、これを行うためのさまざまな方法を提供します。例えば:

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

s-format任意の代用機能を取ることができますが、ために特別な処理を提供しageteltgethash。そのため、次のようにトークンのリストを使用し、インデックスでそれらを参照できます。

(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で一般的な文字列操作タスクを実行する方法を覗きましたが、これは既存の関数の単なる1行のラッパーではありません。
-wasamasa

3

s.elのs-lex-formatは本当に欲しいものですが、変数名だけでなく置換ブロック内に実際にコードを入れたい場合は、これを概念実証として書きました。

(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を使用する代わりに、どの形式タイプを使用するかで改善できますが、実行時に行う必要があり、オーバーヘッドが追加されますが、すべてを適切にフォーマットする関数呼び出しですべての形式引数を囲むことで実行できますタイプではありますが、実際にあなたが望むのはおそらくフロートであり、置換で(format "%f" float)を行うことさえできるのは、あなたが必死だったということです。

もっと取り組むと、この回答の代わりにこの要点を更新する可能性が高くなります。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あなたの例で答えを更新しました。
wvxvw
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.