# How to join all lines together which matching pattern?

I would like to join lines together only for lines which have certain pattern (such as `;`), however when using `g/;/j` it doesn't work as expected unless called couple of times.

For example the following content:

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

when using: `:g/;/j` the output is:

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

or `:g/;/-j` gives:

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

similar with: `:g/;\_.\{-};/j`.

My expected output is:

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

or something similar, so all lines containing the pattern are joined together.

How this can be achieved?

• FWIW, `:g/;/j` doesn't work because it is done in two passes: first the buffer is scanned, then the command is applied to the matching lines. – romainl Dec 31 '15 at 6:59

Possible explanation of the problem

I think the reason why `:g/;/j` doesn't work is because the `:g` command operates with a 2-pass algorithm:

• during the first pass it marks the lines containing the pattern `;`
• during the second pass it operates on the marked lines

During the second pass, `:g` joins the line `1;` with line `2;` because `1;` was marked during the first pass. However I suspect (not sure) that it doesn't join `1; 2;` with `3;` because the line `2;` doesn't exist anymore, its content has been merged with the line `1;` which has already been processed.

So `:g` looks for the next line which was marked during first pass (`3;`) and joins it with the following one (`4;`). After that the problem repeats, it can't join `3; 4;` with `5;` because the line `4;` doesn't exist anymore.

Solution 1 (with vimscript)

Maybe you could call a function whenever a line containing `;` is found to check whether the previous line also contains a semicolon:

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

Then use the following global command:

``````:g/;/call JoinLines()
``````

Or without a function:

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

Solution 2 (without vimscript)

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

Whenever the global command `:g` finds the pattern `;` it executes the command: `.,/^[^;]*\$/-1j`

It can be broken down like this:

``````:g/pattern/a,bj
``````

Where :

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

`b` can be broken down further like this:

``````/    = 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` is the abbreviated form of the Ex command `:join` which like most other Ex commands can be preceded by a range.
Here it's preceded by the range: `.,/^[^;]*\$/-1` (`a,b`)
A range follows the form `a,b` where `a` and `b` are generally 2 line numbers, and allows you to operate on a group of lines whose number is between `a` and `b`, instead of just one.

So the `j` command joins all the lines between the current one (`a`) and the next one which doesn't contain any semicolon minus one (`b`).

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

I do similar joining all the time with a global search and replace:

`s/;\n/;/`

`\n` matches newline.

To find and delete blank lines:

`s/^\$\n//`

I am not sure why, but if want to insert a new line you have to use `\r`

• `s` alone will work only for one line, to make it global, you need to use `%s`, but then it'll join almost all the lines, including non `;` lines – kenorb Jan 1 '16 at 20:39
• @kenorb Ehm no, I think you can use the `:s` command exactly for what you want. I think this `%s/;\n\(.*;\)\@=/;/` does what you need. – Christian Brabandt Jan 1 '16 at 21:01
• @Christian Brabandt Your solution `%s/;\n\(.*;\)\@=/;/` works perfectly, but what is `\@=` ? – Mark Jun 19 at 16:19
• @Mark I just converted your answer to a comment; in doing so, I thought I would point out that you can use `:help` followed by almost anything to get more advice. Even just plain `:help` is very useful. – D. Ben Knoble Jun 19 at 19:36