Elispで文字列をディープコピーしますか?


9

私は適切な文字列を持っています。元の文字列のプロパティを保持しながら、それを深くコピーしてプロパティを追加したいと思います。どうすれば(簡単に)できますか?

1つずつ評価:

(setq test-str-1
      #(";; This `is' a test"
        0 3 (fontified nil face font-lock-comment-delimiter-face)
        3 9 (fontified nil face font-lock-comment-face)
        9 11 (fontified nil face (font-lock-constant-face font-lock-comment-face))
        11 19 (fontified nil face font-lock-comment-face)))
(setq test-str-2 (concat test-str-1))
(add-face-text-property 0 (length test-str-2) 'foobar t test-str-2)

そしてその結果:

test-str-2
;; =>
#(";; This `is' a test" 0 3 (fontified nil face (font-lock-comment-delimiter-face foobar))
  3 9 (fontified nil face (font-lock-comment-face foobar))
  9 11 (fontified nil face (font-lock-constant-face font-lock-comment-face foobar))
  11 19 (fontified nil face (font-lock-comment-face foobar)))
test-str-1
;; =>
#(";; This `is' a test" 0 3 (face font-lock-comment-delimiter-face fontified nil)
  3 9 (face font-lock-comment-face fontified nil)
  9 11 (face (font-lock-constant-face font-lock-comment-face foobar) ; <= foobar is here
        fontified nil)
  11 19 (face font-lock-comment-face fontified nil))

2
私はこれをバグとして報告しadd-face-text-propertyます。リストが他のユーザーによって参照されていると失敗するため、リストを破壊的に変更しないでください。
Lindydancer 2015年


バグを報告していただきありがとうございます。残念ながら、まだ誰もそれに応答していません。このユーティリティ関数(Cでコード化)を修正するとよいでしょう。
2015

回答:


7

関数font-lock-append-text-propertyを使用して、textプロパティを追加できます。値を破壊的に変更することはありません。

例えば:

(setq test-str-1
      #(";; This `is' a test"
        0 3 (fontified nil face font-lock-comment-delimiter-face)
        3 9 (fontified nil face font-lock-comment-face)
        9 11 (fontified nil face (font-lock-constant-face font-lock-comment-face))
        11 19 (fontified nil face font-lock-comment-face)))
(setq test-str-2 (concat test-str-1))
(font-lock-append-text-property 0 (length test-str-2) 'face '(foobar t) test-str-2)


test-str-1
#(";; This `is' a test"
  0 3 (face font-lock-comment-delimiter-face fontified nil)
  3 9 (face font-lock-comment-face fontified nil)
  9 11 (face (font-lock-constant-face font-lock-comment-face) fontified nil)
  11 19 (face font-lock-comment-face fontified nil))

test-str-2
#(";; This `is' a test"
  0 3 (fontified nil face (font-lock-comment-delimiter-face foobar t))
  3 9 (fontified nil face (font-lock-comment-face foobar t))
  9 11 (fontified nil face (font-lock-constant-face font-lock-comment-face foobar t))
  11 19 (fontified nil face (font-lock-comment-face foobar t)))

ここではtest-str-1、は元の値を保持しています。


4

これを行うには、テキストプロパティを繰り返し処理し、基になるプロパティデータをコピーし、既存のプロパティを新しいコピーで上書きします。

(defun deep-copy-text-properties (str)
  (with-temp-buffer
    (insert str)
    (goto-char 1)
    (while (not (eobp))
      (set-text-properties (point)
                           (goto-char (next-char-property-change (point) (point-max)))
                           ;; copy-tree is the important part
                           (copy-tree (text-properties-at (1- (point))))))
    (buffer-string)))

私のテストでは、これはreadソリューションよりも約20%高速でした。また、一時バッファを使用せず、文字列のプロパティを変更したバージョンを作成しましたが、コードは少なくなりますが、速度は遅くなりました。

Cコードを見ると、リスト構造を再構築するが値によって要素をコピーしないcopy_sequenceを使用して、プロパティplistsをコピーします。そのため、リスト値を持つ例のfaceのようなプロパティは、参照によってコピーされ、変更されます。バグかどうかはわからない


2

使用できます(concat the-original-string)

例えば:

(let ((s "TEXT"))
  (set-text-properties 2 3 '(:foreground "blue") s)
  (let ((q (concat s)))
    (add-text-properties 2 3 '(:background "red") q)
    (cons s q)))
;; Returns:
(#("TEXT" 2 3 (:foreground "blue")) . #("TEXT" 2 3 (:foreground "blue" :background "red")))

1
動作しません。例を追加します。
abo-abo

1
トリックは、私と同じように、プロパティにネストされたリストを持つことです。その後、concat動作しません。
abo-abo

@ abo-abo。はい、わかりました。あなたの追加の例ではそれを見つけませんでした。その場合は答えがありませんが、本当に必要な機能だと思います。(1つの潜在的な問題は、未知のプロパティが何らかの共有オブジェクトを参照することを期待するかどうかを知ることが不可能であることです。)
Lindydancer

1

(あまり効率的ではない)回避策が見つかりました:

(setq test-str-2
      (read (prin1-to-string test-str-1)))

2
プロパティに#文字が含まれている場合、回避策は失敗します。
abo-abo

#文字がシンボル名の一部であるということですか?または、バッファまたはその他の印刷不可能なデータであるプロパティを意味しますか?最初の場合は、バグを報告してください。
Malabarba 2015年

プロパティ内のバッファ
abo-abo
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.