วิธีการเข้าร่วมทุกบรรทัดด้วยกันซึ่งเป็นรูปแบบการจับคู่?


12

ฉันต้องการรวมสายเข้าด้วยกันเฉพาะสำหรับบรรทัดที่มีรูปแบบบางอย่าง (เช่น;) อย่างไรก็ตามเมื่อใช้g/;/jมันจะไม่ทำงานอย่างที่คาดไว้เว้นแต่จะเรียกว่าสองครั้ง

ตัวอย่างเช่นเนื้อหาต่อไปนี้:

a
1;
2;
3;
4;
5;
b
6;
7;
8;
9;
c

เมื่อใช้: :g/;/jผลลัพธ์คือ:

a
1; 2;
3; 4;
5; b
6; 7;
8; 9;
c

หรือ:g/;/-jให้:

a 1; 2; 3; 4; 5;
b 6; 7; 8; 9;
c

คล้ายกับ: :g/;\_.\{-};/j.

ผลลัพธ์ที่คาดหวังของฉันคือ:

a 
1; 2; 3; 4; 5;
b
6; 7; 8; 9;
c

หรือบางอย่างที่คล้ายกันดังนั้นทุกบรรทัดที่มีรูปแบบจะถูกรวมเข้าด้วยกัน

วิธีนี้สามารถทำได้?


3
FWIW :g/;/jไม่ทำงานเพราะทำในสองรอบ: ก่อนสแกนบัฟเฟอร์แล้วคำสั่งจะถูกนำไปใช้กับบรรทัดที่ตรงกัน
romainl

คำตอบ:


12

คำอธิบายที่เป็นไปได้ของปัญหา

ฉันคิดว่าเหตุผลที่ทำไม:g/;/jไม่ทำงานเป็นเพราะ:gคำสั่งทำงานด้วยอัลกอริทึม 2 รอบ:

  • ในช่วงแรกที่ผ่านมันทำเครื่องหมายเส้นที่มีรูปแบบ ;
  • ในระหว่างรอบที่สองมันทำงานบนเส้นที่ทำเครื่องหมายไว้

ในระหว่างรอบที่สอง:gเข้าร่วมสาย1;กับสาย2;เพราะ1;ถูกทำเครื่องหมายในระหว่างรอบแรก อย่างไรก็ตามฉันสงสัย (ไม่แน่ใจ) ว่ามันไม่ได้เข้าร่วม1; 2;ด้วย3;เพราะ2;ไม่มีอีกต่อไปแล้วเนื้อหาของมันถูกรวมเข้ากับบรรทัด1;ที่ได้รับการประมวลผลแล้ว

ดังนั้น:gมองหาบรรทัดถัดไปซึ่งถูกทำเครื่องหมายระหว่างการผ่านครั้งแรก ( 3;) และรวมกับหนึ่งบรรทัดต่อไปนี้ ( 4;) หลังจากนั้นซ้ำปัญหาก็ไม่สามารถเข้าร่วม3; 4;ด้วย5;เพราะสาย4;ไม่อยู่อีกต่อไป

โซลูชันที่ 1 (พร้อม vimscript)

บางทีคุณอาจเรียกฟังก์ชันเมื่อใดก็ตามที่;พบบรรทัดที่มีเพื่อตรวจสอบว่าบรรทัดก่อนหน้ามีอัฒภาคอยู่หรือไม่:

function! JoinLines()
    if getline(line('.')-1) =~ ';'
        .-1join
    endif
endfunction

จากนั้นใช้คำสั่งโกลบอลต่อไปนี้:

:g/;/call JoinLines()

หรือไม่มีฟังก์ชั่น:

:g/;/if getline(line('.')-1) =~ ';' | -j | endif

โซลูชันที่ 2 (ไม่มี vimscript)

:g/;/.,/^[^;]*$/-1j

เมื่อใดก็ตามที่คำสั่ง global :gพบรูปแบบ;มันจะรันคำสั่ง: .,/^[^;]*$/-1j

มันสามารถถูกทำลายลงเช่นนี้

:g/pattern/a,bj

ที่ไหน:

pattern = ;
a       = .           = number of current line
b       = /^[^;]*$/-1 = number of next line without any semicolon minus one

b สามารถแยกย่อยได้มากขึ้นเช่นนี้

/    = look for the number of the next line matching the following pattern
^    = a beginning of line
[^;] = then any character except a semicolon
 *   = the last character can be repeated 0 or more times
 $   = an end of line
 /   = end of pattern
 -1  = removes one to the number you just got

jเป็นรูปแบบย่อของคำสั่ง Ex :joinซึ่งเหมือนกับคำสั่ง Ex อื่น ๆ ส่วนใหญ่สามารถนำหน้าด้วยช่วง
ที่นี่มันนำหน้าด้วยช่วง: .,/^[^;]*$/-1( a,b)
ช่วงต่อจากรูปแบบa,bที่aและbโดยทั่วไปคือหมายเลขบรรทัด 2 และช่วยให้คุณสามารถทำงานกับกลุ่มของเส้นที่มีจำนวนอยู่ระหว่างaและbแทนที่จะเป็นเพียงหนึ่ง

ดังนั้นjคำสั่งจะรวมบรรทัดทั้งหมดระหว่างหนึ่งบรรทัดปัจจุบัน ( a) และบรรทัดถัดไปที่ไม่มีเซมิโคลอนใด ๆ ลบหนึ่ง ( b)

สำหรับข้อมูลเพิ่มเติมดู:

:help :global
:help :join
:help :range

2

ฉันเข้าร่วมที่คล้ายกันตลอดเวลาด้วยการค้นหาทั่วโลกและแทนที่:

/ s; \ n /; /

\n ตรงกับบรรทัดใหม่

วิธีค้นหาและลบบรรทัดว่าง:

s / ^ $ \ n //

ฉันไม่แน่ใจว่าทำไม แต่ถ้าต้องการแทรกบรรทัดใหม่คุณต้องใช้ \r


sเพียงอย่างเดียวจะทำงานได้เพียงหนึ่งบรรทัดเพื่อให้เป็นสากลคุณจำเป็นต้องใช้%sแต่จากนั้นจะเข้าร่วมเกือบทุกบรรทัดรวมถึง;บรรทัดที่ไม่ใช่
kenorb

2
@kenorb ใช่มั้ยฉันคิดว่าคุณสามารถใช้:sคำสั่งได้อย่างแม่นยำสำหรับสิ่งที่คุณต้องการ ฉันคิดว่านี่เป็น%s/;\n\(.*;\)\@=/;/สิ่งที่คุณต้องการ
Christian Brabandt
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.