คุณลักษณะการค้นหา / แทนที่เช่นสำหรับการแลกเปลี่ยนข้อความ


12

บ่อยครั้งที่ฉันพบว่าตัวเองพยายามที่จะเข้ามาแทนที่เช่นfooด้วยbarและbarด้วยfooในกันชน

วิธีที่ฉันทำตามปกติคือ:

  • 3 แบบสอบถามแทนที่: aaa -> @@@, bbb -> aaa,@@@ -> bbb
  • ยอมแพ้ในระบบอัตโนมัติและทำการทดแทนด้วยมือ

ฉันคิดว่ามันเป็นไปได้ที่จะได้รับสิ่งที่ทำงานโดยใช้,ไวยากรณ์ในquery-replace-regexpการทดสอบว่าสตริงที่ตรงกันaaaหรือbbbไม่ แต่ไวยากรณ์ที่เกิดขึ้นจะยุ่งยากเกินไปดังนั้นฉันไม่เคยลองเลย

สิ่งที่ได้รับคือความธรรมดาของงานฉันคิดว่าต้องมีขั้นตอนที่ดีกว่าขั้นตอนเดียวในการทำไม่ว่าจะเป็นในตัวหรือในแพ็คเกจที่มีอยู่ มีอะไรบ้าง


อาจมีขั้นตอนเดียว แต่วิธีแรกของคุณไม่เลว IMO และถ้าคุณเลือกสตริงการแทนที่ที่ถูกต้องคุณก็สามารถทำการแทนที่แบบไม่มีเคียวรีสำหรับรอบที่สองได้
ดึง

@ ดึงสำหรับปกติquery-replaceฉันรู้ว่ามันมักจะเร็วM-% str1 str2กว่าที่จะย้ายจุดและทำการเปลี่ยนแปลงด้วยมือ str1มันเป็นเรื่องดีเพราะผมจะได้ไม่ต้องเสียเวลาคิดเกี่ยวกับสิ่งที่จะเป็นเร็วที่สุดแม้ว่าจะมีเพียงคนเดียวคือการเกิดขึ้นของ เป็นการดีที่ฉันต้องการให้การส่งข้อความเป็นไปอย่างรวดเร็วเพื่อให้ฉันสามารถใช้งานได้โดยไม่ต้องคิดเช่นกัน
T. Verron

บางคนจะให้คำตอบง่ายๆ คุณไม่ต้องสงสัยเลยว่าทำสิ่งที่คุณถามเช่นโดยใช้นิพจน์เสียงกระเพื่อมสำหรับการแทนที่โดยอ้างอิงข้อความที่จะถูกแทนที่ (setq a (prog1 b (setq b a)))เช่นการใช้สิ่งที่คล้ายกับสำนวนการแลกเปลี่ยน และอาจมีวิธีที่ง่ายกว่า
ดึง

2
ฉันไม่พบว่า\,(if \1 "b" "a")น่าเกลียดโดยเฉพาะอย่างยิ่ง (เทียบกับ regexp ของ\(a\)\|b) แต่ยังคงต้องพิมพ์คำสองครั้งถ้าที่รบกวนจิตใจคุณ
politza

2
ทำไมไม่\(aaa\)\|bbb?
politza

คำตอบ:


8

นี่คือคำสั่งเล็ก ๆ ที่จะทำสิ่งนี้:

(defun query-swap-strings (from-string to-string &optional delimited start end)
  "Swap occurrences of FROM-STRING and TO-STRING."
  (interactive
   (let ((common
          (query-replace-read-args
           (concat "Query swap"
                   (if current-prefix-arg
                       (if (eq current-prefix-arg '-) " backward" " word")
                     "")
                   (if (use-region-p) " in region" ""))
           nil)))
     (list (nth 0 common) (nth 1 common) (nth 2 common)
           (if (use-region-p) (region-beginning))
           (if (use-region-p) (region-end)))))
  (perform-replace
   (concat "\\(" (regexp-quote from-string) "\\)\\|" (regexp-quote to-string))
   `(replace-eval-replacement replace-quote (if (match-string 1) ,to-string ,from-string))
   t t delimited nil nil start end))

ขอบคุณนั่นเป็นวิธีที่ซับซ้อนกว่าสิ่งที่ฉันจะเขียนเอง! บางทีคุณสามารถอธิบายรายละเอียดเกี่ยวกับคุณสมบัติที่ใช้งานได้? ฉันเห็นว่าด้วยคำนำหน้าอาร์กิวเมนต์ที่คุณย้อนกลับไปมันจะทำการแทนที่เฉพาะในภูมิภาคหากจำเป็น ... หรือมันเป็นเพียงการเขียนใหม่query-replaceสำหรับการกลับรายการเพื่อให้ยังคงคุณลักษณะทั้งหมดไว้หรือไม่ ไม่ตรงกับคำจำกัดความ 100% ใน emacs ของฉัน แต่ฉันยังอยู่กับ 24.5 ...
T. Verron

@ T.Verron นี่เป็นเพียงเนื้อหามาตรฐานจากquery-replaceตระกูลฟังก์ชั่นจากเวอร์ชั่นล่าสุดดังนั้นจึงยังคงคุณลักษณะทั้งหมดไว้ ในตอนท้ายของฟังก์ชั่นฉันเพิ่มวิธีการแลกเปลี่ยนสตริงที่กล่าวถึงในคู่มือ Emacs
link0ff

ฉันอาจจะยอมรับเร็วเกินไป ฟังก์ชั่นใช้งานได้ที่นี่เท่านั้น (emacs 24.3) ถ้าฉันใส่ความคิดเห็นbackwardและregion-noncontiguous-pเรียกperform-replaceจาก เป็นปัญหาทั่วไปหรือหมายความว่าส่วนต่อประสานที่perform-replaceมีการเปลี่ยนแปลงระหว่างรุ่น
T. Verron

ใช่อินเทอร์เฟซมีการเปลี่ยนแปลงด้วย 2 ข้อโต้แย้งเหล่านี้ที่เพิ่มเข้ามาในเวอร์ชันล่าสุดดังนั้นจึงไม่มีอยู่ในรุ่นก่อนหน้านี้
link0ff

2
การแก้ปัญหานี้ก็ดูเหมือนจะดีในขณะนี้
ชื่อ

9

ติดตั้งplur

และเรียกใช้คำสั่ง plur-query-replace

และอินพุต{foo,bar}และการแทนที่{bar,foo}

กดyเพื่อแทนที่เหตุการณ์ที่เกิดขึ้นตามที่ต้องการ

นอกจากนี้ยังมีชุดคำสั่งนี้แบบไม่โต้ตอบและคล้ายกับการค้นหา


ขอบคุณ! จุดประสงค์ของ plur ก็เป็นสิ่งที่ฉันเคยมองหาในบางครั้งฉันจะได้ดูอย่างแน่นอน ความลังเลเพียงอย่างเดียวของฉันนั้นเกิดจากความคิดเห็นของผู้เขียนแพ็คเกจด้านบน ...;)
T. Verron

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