คัดลอกสตริงใน Elisp หรือไม่?


9

ฉันมีสตริงที่ถูกต้อง ฉันต้องการทำสำเนาลึกของมันเพื่อเพิ่มคุณสมบัติมากขึ้นในขณะที่รักษาคุณสมบัติในสายเดิม ฉันจะทำสิ่งนั้นได้อย่างง่ายดาย

ตัวอย่าง

ประเมินหนึ่งต่อหนึ่ง:

(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

1
ตกลงรายงานข้อผิดพลาดที่debbugs.gnu.org/cgi/bugreport.cgi?bug=20153
abo-abo

ขอบคุณสำหรับการรายงานข้อผิดพลาด น่าเสียดายที่ยังไม่มีใครตอบกลับ คงเป็นการดีที่จะได้รับฟังก์ชั่นยูทิลิตี้นี้ (เขียนเป็น C)
Drew

คำตอบ:


7

คุณสามารถใช้ฟังก์ชั่นfont-lock-append-text-propertyเพื่อเพิ่มคุณสมบัติข้อความ มันไม่ได้ปรับเปลี่ยนค่าแบบทำลายล้าง

ตัวอย่างเช่น:

(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 ซึ่งจะสร้างโครงสร้างรายการใหม่ แต่ไม่คัดลอกองค์ประกอบตามค่าดังนั้นคุณสมบัติเช่นใบหน้าในตัวอย่างของคุณที่มีค่ารายการจะถูกคัดลอกโดยอ้างอิงและแก้ไข บั๊กหรือไม่ฉันไม่รู้


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 ตกลงตอนนี้ฉันเห็นแล้ว ฉันไม่เห็นสิ่งนั้นในตัวอย่างที่คุณเพิ่มเข้าไป ในกรณีนี้ฉันไม่มีคำตอบ แต่ฉันคิดว่ามีความต้องการที่แท้จริงสำหรับฟังก์ชั่นดังกล่าว (หนึ่งปัญหาที่อาจเกิดขึ้นก็คือว่ามันเป็นไปไม่ได้ที่จะรู้ว่าสถานที่ให้บริการที่ไม่รู้จักอาจคาดหวังในการอ้างถึงวัตถุที่ใช้ร่วมกันของบางชนิด.)
Lindydancer

1

พบ a (ไม่ค่อยมีประสิทธิภาพ) แก้ไข:

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

2
การหลีกเลี่ยงปัญหาล้มเหลวหาก proprties มี#อักขระ
abo-abo

คุณหมายถึงว่าอักขระ # เป็นส่วนหนึ่งของชื่อสัญลักษณ์หรือไม่ หรือหมายถึงคุณสมบัติที่เป็นบัฟเฟอร์หรือข้อมูลที่ไม่สามารถพิมพ์ได้อื่น ๆ ? หากเป็นครั้งแรกคุณควรยื่นข้อบกพร่อง
Malabarba

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