Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
268 views
in Technique[技术] by (71.8m points)

Join every 3 lines spearated with tab (vim)

I'd like to join every 3 lines of a file with a tab character as separator. How can this be done using Vim?

I'm aware of the macro mechanism, but I?m looking for something more elegant.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

It turns out that this works:

:g/
/,+1s//

The :global will match every line in the buffer (or in the range, if you pass it a range.)

The / / is being used as a regex that will match every line, in this case, on the line break itself. We could have used something like /^/ (or perhaps /./ or /S/ to match non-empty or non-blank lines), here we're using / / since we want to use that pattern in the following :s, so we can omit it there to use the same pattern.

Then, for each line processed by :g, we use a range of that line up to line +1. That means two lines, in this case, current line and next one. Since we want to join three lines, we want to replace the line break on two lines, so from current line up to line +1. (You could generalize that to using + the number of lines in the blocks you want to join, minus two.)

Finally, we perform the substitution s//, which is equivalent to s/ // (using an empty pattern will match the previously used on, in this case the one passed to :g.) This :substitute will replace the matched line breaks with a tab character, effectively joining lines where it matches. Since we're using ranges of two lines, it will only do so two lines at a time, effectively replacing two line breaks, which will join three lines.

This works because the way :global works when there are edits on the affected lines. It first "marks" the lines that should be acted on, but then if the line is no longer there, it will skip it. So while it will first mark every line, when the :s joins every second and third line to the first in a block, the marks on them will no longer be there, so the end result is that :g will not try to process this line again and will move on to the next "marked" line, which will then become the start of the next block.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...