วิธีการย้อนกลับทุก 4 บรรทัด?


13

ก่อนอื่นเลยนี่เป็นโพสต์แรกของฉันที่นี่ฉันอยากจะบอกว่าฉันได้พบว่า VIM เป็นเครื่องมือที่ยอดเยี่ยมและฟอรัมที่นี่จะเป็นประโยชน์อย่างมากในการค้นหาคำตอบของคำถาม ความช่วยเหลือที่ทรงคุณค่า ฉันยังใหม่กับ VIM ดังนั้นทุกสิ่งที่ฉันเรียนรู้มาจากที่นี่

คำถามของฉันคือฉันรู้วิธีย้อนกลับบรรทัดทั้งหมดในไฟล์ (: g / ^ / m0 ท่ามกลางวิธีอื่น ๆ ) แต่มีวิธีย้อนกลับทุก 4 บรรทัดในไฟล์ดังนั้น

line1
line2
line3
line4
line5
line6
line7
line8
...

กลายเป็น

line4
line3
line2
line1
line8
line7
line6
line5
...

คุณสามารถสมมติได้ว่าจะมีหลายบรรทัดใน 4 บรรทัดที่แน่นอนเสมอ


2
เกี่ยวกับ "ps" ของคุณ: หากคุณแทรกช่องว่าง 4 อันที่ด้านหน้าของบรรทัดจะถูกตีความเป็นรหัส (คุณสามารถเลือกข้อความและใช้ปุ่มรูปแบบที่ด้านบน) คุณสามารถค้นหารายละเอียดเพิ่มเติมเกี่ยวกับไอคอนสอบปากคำด้านบน
mMontu

คำตอบ:


15

คำสั่งที่:Reverseอธิบายที่Vim Wikiสามารถใช้สำหรับสิ่งนี้ (คุณอาจรวมไว้ในของคุณ.vimrcเพื่อให้ถาวร):

command! -bar -range=% Reverse <line1>,<line2>g/^/m<line1>-1|nohl

จากนั้นคุณสามารถบันทึกแมโครเพื่อเรียกใช้คำสั่งในทุก ๆ สี่บรรทัด:

qmV3j:Reverse<cr>4jq
1000@m

คำอธิบาย:

  • qm: 'q' ในโหมดปกติเริ่ม (และหยุด) บันทึกแมโครในการลงทะเบียนที่กำหนด (register 'm' ในกรณีนี้ แต่มันอาจเป็นตัวอักษรอื่น ๆ )
  • V: เข้าสู่โหมดภาพและเลือกบรรทัดปัจจุบัน
  • 3j: ขยายการเลือกที่มองเห็นเป็น 3 บรรทัดถัดไป
  • :Reverse<cr>: รันคำสั่ง Reverse ในบรรทัดที่เลือก ( <cr>ที่นี่หมายถึงenterกุญแจ)
  • 4j: ไปที่บรรทัดที่ไม่เปลี่ยนแปลงถัดไป
  • q: หยุดการบันทึกแมโคร
  • 1000@m: เรียกใช้แมโครที่บันทึกไว้ที่ register 'm' 1,000 ครั้ง (คุณสามารถเพิ่มตัวเลขนี้ได้หากไฟล์ของคุณมีขนาดใหญ่กว่า 4000 บรรทัด)

แก้ไข:

ดังที่ได้กล่าวไว้ในความคิดเห็นคุณสามารถใช้มาโครแบบเรียกซ้ำแทนการใช้การนับ:

qmV3j:Reverse<cr>4jq
qM@mq
@m
  • qM: หากรีจิสเตอร์ที่ระบุqเป็นตัวพิมพ์ใหญ่แมโครจะถูกผนวกเข้ากับรีจิสเตอร์ (ซึ่งจะมีประโยชน์เมื่อคุณรู้เมื่อคุณพลาดขั้นตอนสุดท้ายในแมโครที่ซับซ้อน)
  • @m: เรียกใช้แมโครเมื่อลงทะเบียน m
  • q: หยุดผนวกแมโคร

แม้ว่าจะถูกสร้างเป็นแมโครคุณสามารถสร้างคำสั่งสำหรับสิ่งนี้หากเป็นงานทั่วไปในเวิร์กโฟลว์ของคุณ:

function! Reverse4()
   let reg_m = @m
   let @m = '<c-r><c-r>m'
   normal! @m
   let @m = reg_m
endfunction
command! Reverse4 call Reverse4()
  • function! Reverse4()/ endfunction: กำหนดฟังก์ชั่นใหม่
  • let reg_m = @m: บันทึกเนื้อหาปัจจุบันของการลงทะเบียน m
  • let @m = "<c-r><c-r>m": แทรกมาโครใน register m- หมายเหตุที่<c-r>เป็นเครื่องหมายกลุ่มสำหรับCtrl+ rและคุณควรพิมพ์นี้ไม่ใช่คัดลอก / วางดังนั้นบรรทัดของคุณจะคล้ายกับlet @m = 'V3j:Reverse^M4j@m'และจะมีอักขระพิเศษ (^ M)
  • normal! @m: คำสั่งปกติรันอาร์กิวเมนต์ตามที่พิมพ์ในโหมดปกติดังนั้นมันจะเรียกใช้แมโครแบบเรียกซ้ำ
  • let @m = reg_m: คืนค่าเนื้อหาของการลงทะเบียนmดังนั้นคุณไม่จำเป็นต้องจำไว้ว่าการลงทะเบียนนี้กำลังถูกใช้ในฟังก์ชั่นนี้และหลีกเลี่ยงการใช้มัน

  • command! Reverse4 call Reverse4(): สร้างคำสั่งใหม่สำหรับฟังก์ชั่นนี้

ขึ้นอยู่กับความต้องการของคุณคุณสามารถปรับปรุงมันได้เช่น: ส่งอาร์กิวเมนต์ไปยังคำสั่งและฟังก์ชั่นดังนั้นมันจะทำงานกับจำนวนบรรทัดใด ๆ แทนการแก้ไขในกลุ่มของ 4 บรรทัด


แทนการ1000@qสับคุณยังสามารถใช้แมโคร qmqqm ... @mq@mrecursive:
Doorknob

เมื่อฉันพยายามเรียกใช้ "qmV3j: Reverse <cr> 4jq" มันพูดว่า "E492: ไม่ใช่คำสั่งแก้ไข" ฉันต้องทำอะไรผิดไป ฉันใช้ - และเคยใช้ - GVIM มาก่อน ฉันควรจะพูดถึงเรื่องนี้ตั้งแต่แรก
canwasiereisawelba

อ่าไม่เป็นไร ฉันคิดออก - ฉันไม่ควรจะพิมพ์ ":" ก่อนส่วน "qmV3j: ย้อนกลับ <cr> 4jq" มันได้ผล! ขอบคุณมาก mMontu ถ้าฉันอาจถาม - ฉันจะรวมคำสั่ง ": Reverse" ใน. vimrc ของฉันได้อย่างไร
canwasiereisawelba

3
@ablewasiereisawelba หากต้องการให้คำสั่งพร้อมใช้งานอย่างถาวรเพียงแค่เขียนบรรทัดcommand! -bar -range=% Reverse <line1>,<line2>g/^/m<line1>-1|nohlใน vimrc ของคุณ
saginaw

@ saginaw โอ้ฉันไม่รู้เลยว่ามันตรงไปตรงมา ขอขอบคุณ.
canwasiereisawelba

9

เช่นเดียวกับการกระทำที่ทำซ้ำ ๆทั้งหมด หากคุณสามารถทำสิ่งหนึ่งครั้งด้วยการแก้ไขพื้นฐานคุณสามารถทำได้หลายครั้งโดยการบันทึกแมโคร

(ในกรณีนี้ฉันจะใช้มาโครแบบเรียกซ้ำ แต่คุณสามารถบันทึกแบบไม่เรียกซ้ำและเล่นกลับหลาย ๆ ครั้งด้วยการตอก@@หรือโดยใช้การนับ)

ggqqqqqddjjpkddkkPjddpjj@qq@q

พังทลาย

  1. gg: ย้ายไปที่จุดเริ่มต้นของไฟล์
  2. qqq: qล้างออกทะเบียน เราจะเห็นว่าทำไมสิ่งนี้จำเป็นในขั้นตอนที่ 5
  3. qq: เริ่มบันทึกแมโครเพื่อลงทะเบียน q
  4. ddjjpkddkkPjddpjj: ชุดการทำงานที่เรียงลำดับสี่บรรทัดแรกง่ายๆโดยการลบและวางด้วยตนเอง (ซึ่งอาจมีลักษณะซับซ้อนได้อย่างรวดเร็วก่อน แต่ไม่ได้ถูกหลอกนี่คือสิ่งพื้นฐานอย่างที่คุณต้องการได้เรียนรู้ในครั้งแรก 5 นาทีหรือเพื่อการ. vimtutor: j, k, dd, p, P)
  5. @q: เรียกมาโคร! ณ จุดนี้การลงทะเบียนqไม่มีสิ่งใด (เพราะเราล้างข้อมูลในขั้นตอนที่ 2) ดังนั้นจึงไม่มีอะไรเกิดขึ้น
  6. q: หยุดบันทึกแมโคร
  7. @q: เล่นซ้ำซ้ำได้หลายครั้งตามที่จำเป็น

NB ข้างต้นจะไม่ให้ผลลัพธ์ที่ต้องการหากไฟล์มีจำนวนบรรทัดที่ไม่สามารถหารด้วยสี่ เพื่อหยุดแมโครก่อนเวลาหากไม่มีเหลืออีกสี่บรรทัดเราต้องดำเนินการคำสั่งโหมดปกติของ Vim ที่จะล้มเหลวก่อนที่เราจะเริ่มใช้การแก้ไขในขั้นตอนที่ 4 เราสามารถทำได้โดยพยายามเลื่อนลง บรรทัดที่สามครั้ง (แล้วสำรองข้อมูล) ก่อนที่เราจะเริ่มย้ายเส้นรอบ ๆ :jjj3k

ดังนั้น:

ggqqqqqjjj3kddjjpkddkkPjddpjj@qq@q

เหตุใดคุณจึงล้างการลงทะเบียน q อย่างชัดเจน หากคุณเพิ่งบันทึกลงไปสิ่งที่อยู่ในนั้นจะถูกเขียนทับอยู่แล้ว ....
ไวลด์การ์ด

4
@Wildcard เนื่องจากเป็นมาโครแบบเรียกซ้ำครั้งแรกที่คุณเรียกเนื้อหาของการลงทะเบียนqจะต้องว่างเปล่ามิฉะนั้นจะทำให้รุ่นของคุณยุ่งเหยิง
saginaw

ดีมาก. ฉันพยายามโต้ตอบโดยไม่พยายามพิมพ์ลำดับที่แน่นอนของคำสั่งของคุณและทำให้การใช้:qqqggqqjjjkddkkPjddjpkddkkPjjjj@qq@q
Wildcard

1
@ablewasiereisawelba where I can just use the one-line custom command each time I need to do this- โปรดทราบว่าคุณไม่จำเป็นต้องสร้างแมโครใหม่ทุกครั้งที่คุณต้องการใช้เนื่องจากคุณสามารถจัดเก็บเป็นฟังก์ชัน / คำสั่งบน vimrc ของคุณได้
mMontu

1
@ablewasiereisawelba ฉันดีใจที่คุณพบว่า "แก้ไข" มีประโยชน์! เนื่องจากนี่เป็นโพสต์แรกของคุณที่นี่บางทีคุณอาจไม่ทราบว่าการแจ้งเตือน StackExchange ทำงานอย่างไร: เมื่อคุณโพสต์ความคิดเห็นผู้เขียนคำตอบ / คำถามจะได้รับการแจ้งเตือน บุคคลอื่นจะได้รับการแจ้งเตือนเฉพาะเมื่อคุณใส่ @ <nick> ดังนั้น Rich จึงได้รับการแจ้งเตือนเกี่ยวกับข้อความล่าสุดของคุณ
mMontu

7

คุณสามารถทำได้ด้วยExคำสั่งที่ใช้sedเป็นตัวกรองภายนอก:

:%!sed -n 'h;n;G;h;n;G;h;n;G;p'

รุ่นนี้จะละเว้น (ลบ) บรรทัดพิเศษใด ๆ ที่เกินกว่า 4 เท่าเพื่อให้อยู่ในชุดสุดท้ายของน้อยกว่า 4 บรรทัด (กลับด้าน) ให้ใช้:

:%!sed -n '$p;h;n;G;$p;h;n;G;$p;h;n;G;p'

%ที่นี่หมายถึง "เส้นในบัฟเฟอร์ทุกคน."

!คำสั่งหมายถึง "เรียกใช้คำสั่งต่อไปนี้ที่มีเส้นที่ระบุเป็น input และเปลี่ยนสายที่ระบุกับการส่งออกของคำสั่ง." (มันเรียกว่าตัวกรองซึ่งมีประโยชน์มากสำหรับสิ่งต่าง ๆ เช่นการเรียงลำดับเช่น:%!sortจะเรียงลำดับบรรทัดทั้งหมดในไฟล์ของคุณ:2,8!sortจะเรียงลำดับบรรทัด 2-8 เป็นต้น)

sedเป็นเครื่องมือแก้ไขสตรีมและพบได้ในทุกระบบของ Unix แนวคิดหลักของการsedใช้ที่นี่คือ "pattern space" (ซึ่งโดยปกติแล้วจะประกอบด้วยแต่ละบรรทัดของอินพุตในทางกลับกัน) และ "hold space" (ซึ่งเป็นที่ที่คุณสามารถติดข้อความพิเศษในขณะที่ใช้sedเพื่อบันทึกขณะประมวลผลอื่น ๆ บรรทัดอินพุต)

-nเป็นตัวเลือกให้กับsedคำสั่งเพื่อระงับการกระทำเริ่มต้นของการพิมพ์พื้นที่รูปแบบ (เพราะในกรณีนี้เราต้องการพิมพ์เฉพาะเมื่อเราพูดอย่างชัดเจนเท่านั้น)

$pในsedคำสั่งหมายถึง "ถ้าคุณอยู่ในบรรทัดสุดท้ายของsedอินพุตให้พิมพ์ (พื้นที่รูปแบบ)"

h หมายถึง "ติดเนื้อหาปัจจุบันของ 'pattern space' ใน 'hold space' โดยเขียนทับอะไรก็ตามที่อยู่ที่นั่น"

n หมายถึง "แทนที่เนื้อหาของ 'pattern space' ด้วยบรรทัดถัดไปจากอินพุต"

G หมายถึง "ผนวกเข้ากับ 'pattern space': ขึ้นบรรทัดใหม่ตามด้วยเนื้อหาของ 'hold space'"

เมื่อรวมเข้าด้วยกันsedคำสั่งจะเก็บเอาต์พุตสี่บรรทัดย้อนกลับขณะที่มันจัดเก็บแล้วพิมพ์ออกมา $pคำสั่งเพิ่มในรุ่นที่สองให้มั่นใจว่าถ้าบรรทัดสุดท้ายของไฟล์จะถึงอื่น ๆ กว่าหลาย 4 เส้นเส้นยังคงพิมพ์


สำหรับทางเลือกวิธีการอินเทอร์แอคทีฟยังคงไม่ใช้คุณลักษณะเฉพาะของ Vim และโดยไม่ต้องใช้ตัวกรองภายนอก:

:4

เพื่อไปที่บรรทัดที่สี่

:.m -4 | +3m . | +2m . | +5

เพื่อย้อนกลับสี่บรรทัดก่อนหน้า (1-4) และปล่อยเคอร์เซอร์ของคุณไว้ที่บรรทัดที่ 8

.m -4ย้ายบรรทัดปัจจุบันไปหลังบรรทัดสี่บรรทัดย้อนกลับ (ปล่อยเคอร์เซอร์บนบรรทัดที่ย้าย)

+3m .ย้ายสายที่ 3 สายหลังจากบรรทัดปัจจุบันเพื่อเพียงหลังจากบรรทัดปัจจุบันออกจากเคอร์เซอร์บนเส้นย้าย +2m .แน่นอนทำงานเหมือนกัน

+5 วางเคอร์เซอร์ลงห้าบรรทัดจากตำแหน่งที่มันอยู่

ทำซ้ำตามที่ต้องการ

ในกลุ่มคุณสามารถทำซ้ำคำสั่งทั้งหมดนี้ด้วยแล้วทำซ้ำอีกครั้งกับ@: @@ใน POSIX viหรือexคุณต้องการแทรก :.m -4 | +3m . | +2m . | +5เป็นบรรทัดข้อความให้ลบลงในบัฟเฟอร์ที่มีชื่อ (รีจิสเตอร์) จากนั้นดำเนินการบัฟเฟอร์ที่มีชื่อ (รีจิสเตอร์)

ดังนั้นในexโหมดการย้อนกลับบรรทัดแบบโต้ตอบโดยใช้คุณลักษณะที่ระบุ POSIX เท่านั้นและเริ่มต้นด้วยข้อความ 17 บรรทัด:

Entering Ex mode.  Type "visual" to go to Normal mode.
:0a     # Append following text after "line 0" (i.e. insert at start of file).
.m -4 | +3m . | +2m . | +5
.       # End text insertion
:d k    # Delete that line to register k
line1   # This is a printout of the current line
:4      # Move to line 4
line4
:@k     # Execute register k to reverse lines 1-4
line8
:@@     # Execute register k again
line12
:@@     # Execute register k again
line16
:@@     # Execute register k again
line17
:%p     # Print the whole buffer (just to see what was done)
line4
line3
line2
line1
line8
line7
line6
line5
line12
line11
line10
line9
line16
line15
line14
line13
line17
:wq     # Save and quit

อ่านเพิ่มเติม:


คุณช่วยอธิบายวิธีแก้ปัญหาของคุณให้มากขึ้นได้ไหม?
vappolinario

3
@ vappolinario ฉันได้เพิ่มคำอธิบายเพิ่มเติม มันช่วยได้ไหม :)
สัญลักษณ์แทน

ว้าวคำตอบที่ยาวมาก :) ฉันรู้สึกแย่จริง ๆ แล้ว แต่ฉันเพิ่งใช้มันกับสคริปต์ง่ายๆที่ฉันพบที่ไหนสักแห่ง - อาจเป็นบนกระดานนี้ - นั่นเป็นวิธีแก้ปัญหาที่ฉันมี อย่างไรก็ตามเมื่อฉันพยายามรันบรรทัดที่คุณแนะนำมันบอกว่า "'sed' ไม่ได้รับการยอมรับว่าเป็นคำสั่งภายในหรือภายนอก, โปรแกรมที่ทำงานได้หรือแบตช์ไฟล์" ฉันไม่แน่ใจว่าฉันต้องมีสติในโฟลเดอร์เสียงเรียกเข้าหรือไม่
canwasiereisawelba

1
@ablewasiereisawelba ถ้าคุณกำลังทำงานอยู่บนกล่อง Windows และไม่ได้ใช้ Cygwin (หรือ MobaXterm หรือคล้ายกัน), คุณอาจจะลองวิธีอื่น ๆ ที่ฉันให้: 4G:.m -4 | +3m . | +2m . | +5<Enter>@:แล้ว@@ซ้ำจนกว่าไฟล์ของคุณจะถูกประมวลผลอย่างเต็มที่ ฉันแนะนำให้ติดตั้ง MobaXterm :)
สัญลักษณ์แทน

@ Wildcard โอเคฉันกำลังตรวจสอบ MobaXterm ตอนนี้ :)
canwasiereisawelba

7
:g/^/exe 'm .-' . substitute(line('.') % 4, '^0$', '4', '')

ภาษาอังกฤษธรรมดา: ทุกบรรทัดย้ายบรรทัดปัจจุบันขึ้นlnum % 4เว้นแต่ในกรณีที่ย้ายบรรทัดปัจจุบันขึ้นlnum % 4 == 04

นอกจากนี้จะย้อนกลับทุกnสายแทนที่'ในคำสั่งดังกล่าวด้วย4n


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