Sao chép sâu một chuỗi trong Elisp?


9

Tôi có một chuỗi thích hợp. Tôi muốn tạo một bản sao sâu của nó để thêm nhiều thuộc tính, trong khi vẫn giữ các thuộc tính trong chuỗi gốc. Làm thế nào tôi có thể làm điều đó (dễ dàng)?

Thí dụ

Đánh giá từng cái một:

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

Và kết quả:

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
Tôi sẽ báo cáo đây là một lỗi trong add-face-text-property. Nó không nên sửa đổi danh sách một cách triệt để, vì nó thất bại khi danh sách đó được người khác nhắc đến.
Lindydancer 20/03/2015

1
OK, đã báo cáo lỗi tại debbugs.gnu.org/cgi/ormsreport.cgi?orms=20153
abo-abo

Cảm ơn đã báo cáo lỗi. Quá tệ chưa có ai trả lời nó. Sẽ rất tốt nếu có chức năng tiện ích này (được mã hóa bằng C).
vẽ

Câu trả lời:


7

Bạn có thể sử dụng chức năng font-lock-append-text-propertyđể thêm thuộc tính văn bản. Nó không sửa đổi giá trị một cách triệt để.

Ví dụ:

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

Ở đây, trong test-str-1, đã giữ lại giá trị ban đầu của nó.


4

Tôi thấy bạn có thể làm điều này bằng cách lặp lại các thuộc tính văn bản, sao chép dữ liệu thuộc tính cơ bản và ghi đè các thuộc tính hiện có bằng các bản sao mới.

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

Trong các thử nghiệm của tôi, điều này nhanh hơn khoảng 20% ​​so với readgiải pháp của bạn . Tôi cũng đã viết một phiên bản không sử dụng bộ đệm tạm thời và sửa đổi các thuộc tính của một chuỗi ít mã hơn nhưng chậm hơn.

Nhìn vào mã C, nó sao chép các thuộc tính, với copy_ resultence sẽ xây dựng lại cấu trúc danh sách nhưng không sao chép các phần tử theo giá trị, do đó các thuộc tính như khuôn mặt trong ví dụ của bạn có giá trị danh sách được sao chép qua tham chiếu và sửa đổi. Lỗi hay không, tôi không biết


2

Bạn có thể sử dụng (concat the-original-string).

Ví dụ:

(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
Không hoạt động, tôi sẽ thêm một ví dụ.
abo-abo

1
Bí quyết là có một danh sách lồng nhau trong các thuộc tính, giống như tôi làm. Sau đó concatkhông hoạt động.
abo-abo

@ abo-abo. Ok, bây giờ tôi thấy. Tôi đã không nhận ra rằng trong ví dụ thêm vào của bạn. Trong trường hợp đó tôi không có câu trả lời, nhưng tôi nghĩ có một nhu cầu thực sự cho chức năng như vậy. (Một vấn đề tiềm ẩn là không thể biết liệu một tài sản không xác định có thể dự kiến ​​đề cập đến một đối tượng chung nào đó hay không.)
Lindydancer 20/03/2015

1

Tìm thấy một công việc (không hiệu quả lắm):

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

2
Các công việc xung quanh thất bại nếu propries chứa #nhân vật.
abo-abo

bạn có nghĩa là nếu ký tự # là một phần của tên biểu tượng? Hoặc có nghĩa là các thuộc tính là bộ đệm hoặc dữ liệu không thể in khác? Nếu đó là lần đầu tiên, bạn nên báo lỗi.
Malabarba

bộ đệm trong các thuộc tính
abo-abo
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.